diff --git a/api/system/backup.go b/api/system/backup.go new file mode 100644 index 00000000..e3555b5a --- /dev/null +++ b/api/system/backup.go @@ -0,0 +1,161 @@ +package system + +import ( + "bytes" + "encoding/base64" + "net/http" + "os" + "path/filepath" + "strings" + "time" + + "github.com/0xJacky/Nginx-UI/api" + "github.com/0xJacky/Nginx-UI/internal/backup" + "github.com/gin-gonic/gin" + "github.com/jpillora/overseer" + "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"` +} + +// CreateBackup creates a backup of nginx-ui and nginx configurations +// and sends files directly for download +func CreateBackup(c *gin.Context) { + result, err := backup.Backup() + if err != nil { + api.ErrHandler(c, err) + return + } + + // Concatenate Key and IV + securityToken := result.AESKey + ":" + result.AESIv + + // Prepare response content + reader := bytes.NewReader(result.BackupContent) + modTime := time.Now() + + // Set HTTP headers for file download + fileName := result.BackupName + c.Header("Content-Description", "File Transfer") + c.Header("Content-Type", "application/zip") + c.Header("Content-Disposition", "attachment; filename="+fileName) + c.Header("Content-Transfer-Encoding", "binary") + c.Header("X-Backup-Security", securityToken) // Pass security token in header + c.Header("Expires", "0") + c.Header("Cache-Control", "must-revalidate") + c.Header("Pragma", "public") + + // Send file content + http.ServeContent(c.Writer, c.Request, fileName, modTime, reader) +} + +// 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 { + api.ErrHandler(c, cosy.WrapErrorWithParams(backup.ErrBackupFileNotFound, err.Error())) + return + } + + // Validate security token + if securityToken == "" { + api.ErrHandler(c, backup.ErrInvalidSecurityToken) + return + } + + // Split security token to get Key and IV + parts := strings.Split(securityToken, ":") + if len(parts) != 2 { + api.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 { + api.ErrHandler(c, cosy.WrapErrorWithParams(backup.ErrInvalidAESKey, err.Error())) + return + } + + iv, err := base64.StdEncoding.DecodeString(aesIv) + if err != nil { + api.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 { + api.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 { + api.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 { + api.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) + api.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 restoreNginxUI { + go func() { + time.Sleep(3 * time.Second) + // gracefully restart + overseer.Restart() + }() + } + + c.JSON(http.StatusOK, RestoreResponse{ + NginxUIRestored: result.NginxUIRestored, + NginxRestored: result.NginxRestored, + HashMatch: result.HashMatch, + }) +} diff --git a/api/system/backup_test.go b/api/system/backup_test.go new file mode 100644 index 00000000..eb678733 --- /dev/null +++ b/api/system/backup_test.go @@ -0,0 +1,390 @@ +package system + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "io" + "mime/multipart" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/0xJacky/Nginx-UI/internal/backup" + "github.com/0xJacky/Nginx-UI/settings" + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/uozi-tech/cosy/logger" + cosysettings "github.com/uozi-tech/cosy/settings" +) + +// MockBackupService is used to mock the backup service +type MockBackupService struct { + mock.Mock +} + +func (m *MockBackupService) Backup() (backup.BackupResult, error) { + return backup.BackupResult{ + BackupName: "backup-test.zip", + AESKey: "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=", // base64 encoded test key + AESIv: "YWJjZGVmZ2hpamtsbW5vcA==", // base64 encoded test IV + BackupContent: []byte("test backup content"), + }, nil +} + +func (m *MockBackupService) Restore(options backup.RestoreOptions) (backup.RestoreResult, error) { + return backup.RestoreResult{ + RestoreDir: options.RestoreDir, + NginxUIRestored: options.RestoreNginxUI, + NginxRestored: options.RestoreNginx, + HashMatch: options.VerifyHash, + }, nil +} + +// MockedCreateBackup is a mocked version of CreateBackup that uses the mock service +func MockedCreateBackup(c *gin.Context) { + mockService := &MockBackupService{} + result, err := mockService.Backup() + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "error": err.Error(), + }) + return + } + + // Concatenate Key and IV + securityToken := result.AESKey + ":" + result.AESIv + + // Set HTTP headers for file download + fileName := result.BackupName + c.Header("Content-Description", "File Transfer") + c.Header("Content-Type", "application/zip") + c.Header("Content-Disposition", "attachment; filename="+fileName) + c.Header("Content-Transfer-Encoding", "binary") + c.Header("X-Backup-Security", securityToken) // Pass security token in header + c.Header("Expires", "0") + c.Header("Cache-Control", "must-revalidate") + c.Header("Pragma", "public") + + // Send file content + c.Data(http.StatusOK, "application/zip", result.BackupContent) +} + +// MockedRestoreBackup is a mocked version of RestoreBackup that uses the mock service +func MockedRestoreBackup(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 backup file - we're just checking it exists for the test + _, err := c.FormFile("backup_file") + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "error": "Backup file not found", + }) + return + } + + // Validate security token + if securityToken == "" { + c.JSON(http.StatusBadRequest, gin.H{ + "error": "Invalid security token", + }) + return + } + + // Split security token to get Key and IV + parts := strings.Split(securityToken, ":") + if len(parts) != 2 { + c.JSON(http.StatusBadRequest, gin.H{ + "error": "Invalid security token format", + }) + return + } + + // Create temporary directory + tempDir, err := os.MkdirTemp("", "nginx-ui-restore-test-*") + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "error": "Failed to create temporary directory", + }) + return + } + + mockService := &MockBackupService{} + result, err := mockService.Restore(backup.RestoreOptions{ + RestoreDir: tempDir, + RestoreNginx: restoreNginx, + RestoreNginxUI: restoreNginxUI, + VerifyHash: verifyHash, + }) + + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "error": err.Error(), + }) + return + } + + c.JSON(http.StatusOK, RestoreResponse{ + NginxUIRestored: result.NginxUIRestored, + NginxRestored: result.NginxRestored, + HashMatch: result.HashMatch, + }) +} + +func TestSetupEnvironment(t *testing.T) { + logger.Init(gin.DebugMode) + // Set up test environment + tempDir, err := os.MkdirTemp("", "nginx-ui-test-*") + assert.NoError(t, err) + defer os.RemoveAll(tempDir) + + // Set up necessary directories and config files + nginxDir := filepath.Join(tempDir, "nginx") + configDir := filepath.Join(tempDir, "config") + + err = os.MkdirAll(nginxDir, 0755) + assert.NoError(t, err) + + err = os.MkdirAll(configDir, 0755) + assert.NoError(t, err) + + // Create a config.ini file + configPath := filepath.Join(configDir, "config.ini") + err = os.WriteFile(configPath, []byte("[app]\nName = Nginx UI Test\n"), 0644) + assert.NoError(t, err) + + // Create a database file + dbName := settings.DatabaseSettings.GetName() + dbPath := filepath.Join(configDir, dbName+".db") + err = os.WriteFile(dbPath, []byte("test database content"), 0644) + assert.NoError(t, err) + + // Save original settings for restoration later + originalConfigDir := settings.NginxSettings.ConfigDir + originalConfPath := cosysettings.ConfPath + + t.Logf("Original config path: %s", cosysettings.ConfPath) + t.Logf("Setting config path to: %s", configPath) + + // Set the temporary directory as the Nginx config directory for testing + settings.NginxSettings.ConfigDir = nginxDir + cosysettings.ConfPath = configPath + + t.Logf("Config path after setting: %s", cosysettings.ConfPath) + + // Restore original settings after test + defer func() { + settings.NginxSettings.ConfigDir = originalConfigDir + cosysettings.ConfPath = originalConfPath + }() +} + +func setupMockedRouter() *gin.Engine { + gin.SetMode(gin.TestMode) + r := gin.New() + + // Setup router with mocked API endpoints to avoid environment issues + systemGroup := r.Group("/api/system") + systemGroup.POST("/backup", MockedCreateBackup) + systemGroup.POST("/backup/restore", MockedRestoreBackup) + + return r +} + +func TestCreateBackupAPI(t *testing.T) { + // Set up test environment + TestSetupEnvironment(t) + + router := setupMockedRouter() + w := httptest.NewRecorder() + req, _ := http.NewRequest("POST", "/api/system/backup", nil) + router.ServeHTTP(w, req) + + // If there's an error, it might be because the config path is empty + if w.Code != http.StatusOK { + var errorResponse map[string]interface{} + err := json.Unmarshal(w.Body.Bytes(), &errorResponse) + if err == nil { + t.Logf("Error response: %v", errorResponse) + } + + // Skip the test if there's a configuration issue + if strings.Contains(w.Body.String(), "Config path is empty") { + t.Skip("Skipping test due to empty config path") + return + } + } + + // Check response code - should be OK + assert.Equal(t, http.StatusOK, w.Code) + + // Verify the backup API response + assert.Equal(t, "application/zip", w.Header().Get("Content-Type")) + + // Check that Content-Disposition contains "attachment; filename=backup-" + contentDisposition := w.Header().Get("Content-Disposition") + assert.True(t, strings.HasPrefix(contentDisposition, "attachment; filename=backup-"), + "Content-Disposition should start with 'attachment; filename=backup-'") + + assert.NotEmpty(t, w.Header().Get("X-Backup-Security")) + assert.NotEmpty(t, w.Body.Bytes()) + + // Verify security token format + securityToken := w.Header().Get("X-Backup-Security") + parts := bytes.Split([]byte(securityToken), []byte(":")) + assert.Equal(t, 2, len(parts)) + + // Verify key and IV can be decoded + key, err := base64.StdEncoding.DecodeString(string(parts[0])) + assert.NoError(t, err) + assert.Equal(t, 32, len(key)) + + iv, err := base64.StdEncoding.DecodeString(string(parts[1])) + assert.NoError(t, err) + assert.Equal(t, 16, len(iv)) +} + +func TestRestoreBackupAPI(t *testing.T) { + // Set up test environment + TestSetupEnvironment(t) + + // First create a backup to restore + backupRouter := setupMockedRouter() + w1 := httptest.NewRecorder() + req1, _ := http.NewRequest("POST", "/api/system/backup", nil) + backupRouter.ServeHTTP(w1, req1) + + // If there's an error creating the backup, skip the test + if w1.Code != http.StatusOK { + var errorResponse map[string]interface{} + err := json.Unmarshal(w1.Body.Bytes(), &errorResponse) + if err == nil { + t.Logf("Error response during backup creation: %v", errorResponse) + } + t.Skip("Skipping test due to backup creation failure") + return + } + + assert.Equal(t, http.StatusOK, w1.Code) + + // Get the security token from the backup response + securityToken := w1.Header().Get("X-Backup-Security") + assert.NotEmpty(t, securityToken) + + // Get backup content + backupContent := w1.Body.Bytes() + assert.NotEmpty(t, backupContent) + + // Setup temporary directory and save backup file + tempDir, err := os.MkdirTemp("", "restore-api-test-*") + assert.NoError(t, err) + defer os.RemoveAll(tempDir) + + backupName := "backup-test.zip" + backupPath := filepath.Join(tempDir, backupName) + err = os.WriteFile(backupPath, backupContent, 0644) + assert.NoError(t, err) + + // Setup router + router := setupMockedRouter() + + // Create multipart form + body := new(bytes.Buffer) + writer := multipart.NewWriter(body) + + // Add form fields + _ = writer.WriteField("restore_nginx", "false") + _ = writer.WriteField("restore_nginx_ui", "false") + _ = writer.WriteField("verify_hash", "true") + _ = writer.WriteField("security_token", securityToken) + + // Add backup file + file, err := os.Open(backupPath) + assert.NoError(t, err) + defer file.Close() + + part, err := writer.CreateFormFile("backup_file", backupName) + assert.NoError(t, err) + + _, err = io.Copy(part, file) + assert.NoError(t, err) + + err = writer.Close() + assert.NoError(t, err) + + // Create request + w := httptest.NewRecorder() + req, _ := http.NewRequest("POST", "/api/system/backup/restore", body) + req.Header.Set("Content-Type", writer.FormDataContentType()) + + // Perform request + router.ServeHTTP(w, req) + + // Check status code + t.Logf("Response: %s", w.Body.String()) + assert.Equal(t, http.StatusOK, w.Code) + + // Verify response structure + var response RestoreResponse + err = json.Unmarshal(w.Body.Bytes(), &response) + assert.NoError(t, err) + + assert.Equal(t, false, response.NginxUIRestored) + assert.Equal(t, false, response.NginxRestored) + assert.Equal(t, true, response.HashMatch) +} + +func TestRestoreBackupAPIErrors(t *testing.T) { + // Set up test environment + TestSetupEnvironment(t) + + // Setup router + router := setupMockedRouter() + + // Test case 1: Missing backup file + w1 := httptest.NewRecorder() + body1 := new(bytes.Buffer) + writer1 := multipart.NewWriter(body1) + _ = writer1.WriteField("security_token", "invalid:token") + writer1.Close() + + req1, _ := http.NewRequest("POST", "/api/system/backup/restore", body1) + req1.Header.Set("Content-Type", writer1.FormDataContentType()) + + router.ServeHTTP(w1, req1) + assert.NotEqual(t, http.StatusOK, w1.Code) + + // Test case 2: Invalid security token + w2 := httptest.NewRecorder() + body2 := new(bytes.Buffer) + writer2 := multipart.NewWriter(body2) + _ = writer2.WriteField("security_token", "invalidtoken") // No colon separator + writer2.Close() + + req2, _ := http.NewRequest("POST", "/api/system/backup/restore", body2) + req2.Header.Set("Content-Type", writer2.FormDataContentType()) + + router.ServeHTTP(w2, req2) + assert.NotEqual(t, http.StatusOK, w2.Code) + + // Test case 3: Invalid base64 encoding + w3 := httptest.NewRecorder() + body3 := new(bytes.Buffer) + writer3 := multipart.NewWriter(body3) + _ = writer3.WriteField("security_token", "invalid!base64:alsoinvalid!") + writer3.Close() + + req3, _ := http.NewRequest("POST", "/api/system/backup/restore", body3) + req3.Header.Set("Content-Type", writer3.FormDataContentType()) + + router.ServeHTTP(w3, req3) + assert.NotEqual(t, http.StatusOK, w3.Code) +} diff --git a/api/system/router.go b/api/system/router.go index e0b019b7..8f27691b 100644 --- a/api/system/router.go +++ b/api/system/router.go @@ -16,6 +16,10 @@ func InitPrivateRouter(r *gin.RouterGroup) { r.GET("upgrade/current", GetCurrentVersion) r.GET("self_check", SelfCheck) r.POST("self_check/:name/fix", SelfCheckFix) + + // Backup and restore endpoints + r.GET("system/backup", CreateBackup) + r.POST("system/backup/restore", RestoreBackup) } func InitWebSocketRouter(r *gin.RouterGroup) { diff --git a/app/components.d.ts b/app/components.d.ts index 644116b1..ad445731 100644 --- a/app/components.d.ts +++ b/app/components.d.ts @@ -70,6 +70,7 @@ declare module 'vue' { ATag: typeof import('ant-design-vue/es')['Tag'] ATextarea: typeof import('ant-design-vue/es')['Textarea'] ATooltip: typeof import('ant-design-vue/es')['Tooltip'] + AUploadDragger: typeof import('ant-design-vue/es')['UploadDragger'] BreadcrumbBreadcrumb: typeof import('./src/components/Breadcrumb/Breadcrumb.vue')['default'] ChartAreaChart: typeof import('./src/components/Chart/AreaChart.vue')['default'] ChartRadialBarChart: typeof import('./src/components/Chart/RadialBarChart.vue')['default'] diff --git a/app/src/api/backup.ts b/app/src/api/backup.ts new file mode 100644 index 00000000..1b0aff6b --- /dev/null +++ b/app/src/api/backup.ts @@ -0,0 +1,56 @@ +import http from '@/lib/http' + +/** + * Interface for restore backup response + */ +export interface RestoreResponse { + restore_dir: string + nginx_ui_restored: boolean + nginx_restored: boolean + hash_match: boolean +} + +/** + * Interface for restore backup options + */ +export interface RestoreOptions { + backup_file: File + security_token: string + restore_nginx: boolean + restore_nginx_ui: boolean + verify_hash: boolean +} + +const backup = { + /** + * Create and download a backup of nginx-ui and nginx configurations + * Use http module with returnFullResponse option to access headers + */ + createBackup() { + return http.get('/system/backup', { + responseType: 'blob', + returnFullResponse: true, + }) + }, + + /** + * Restore from a backup file + * @param options RestoreOptions + */ + restoreBackup(options: RestoreOptions) { + const formData = new FormData() + formData.append('backup_file', options.backup_file) + formData.append('security_token', options.security_token) + formData.append('restore_nginx', options.restore_nginx.toString()) + formData.append('restore_nginx_ui', options.restore_nginx_ui.toString()) + formData.append('verify_hash', options.verify_hash.toString()) + + return http.post('/system/backup/restore', formData, { + headers: { + 'Content-Type': 'multipart/form-data;charset=UTF-8', + }, + }) + }, +} + +export default backup diff --git a/app/src/constants/errors/backup.ts b/app/src/constants/errors/backup.ts new file mode 100644 index 00000000..28ced19d --- /dev/null +++ b/app/src/constants/errors/backup.ts @@ -0,0 +1,55 @@ +export default { + 4002: () => $gettext('Failed to create temporary directory'), + 4003: () => $gettext('Failed to create temporary subdirectory'), + 4004: () => $gettext('Failed to backup Nginx UI files: {0}'), + 4005: () => $gettext('Failed to backup Nginx config files: {0}'), + 4006: () => $gettext('Failed to create hash info file: {0}'), + 4007: () => $gettext('Failed to encrypt Nginx UI directory: {0}'), + 4008: () => $gettext('Failed to encrypt Nginx directory: {0}'), + 4009: () => $gettext('Failed to create zip archive: {0}'), + 4011: () => $gettext('Failed to generate AES key: {0}'), + 4012: () => $gettext('Failed to generate initialization vector: {0}'), + 4013: () => $gettext('Failed to create backup file: {0}'), + 4101: () => $gettext('Config path is empty'), + 4102: () => $gettext('Failed to copy config file: {0}'), + 4103: () => $gettext('Failed to copy database directory: {0}'), + 4104: () => $gettext('Failed to copy database file: {0}'), + 4105: () => $gettext('Failed to calculate hash: {0}'), + 4106: () => $gettext('Nginx config directory is not set'), + 4107: () => $gettext('Failed to copy Nginx config directory: {0}'), + 4201: () => $gettext('Failed to read file: {0}'), + 4202: () => $gettext('Failed to encrypt file: {0}'), + 4203: () => $gettext('Failed to write encrypted file: {0}'), + 4204: () => $gettext('Failed to encrypt data: {0}'), + 4205: () => $gettext('Failed to decrypt data: {0}'), + 4206: () => $gettext('Invalid padding in decrypted data'), + 4301: () => $gettext('Failed to create zip file: {0}'), + 4302: () => $gettext('Failed to create zip entry: {0}'), + 4303: () => $gettext('Failed to open source file: {0}'), + 4304: () => $gettext('Failed to create zip header: {0}'), + 4305: () => $gettext('Failed to copy file content: {0}'), + 4306: () => $gettext('Failed to write to zip buffer: {0}'), + 4501: () => $gettext('Failed to create restore directory: {0}'), + 4505: () => $gettext('Failed to extract archive: {0}'), + 4506: () => $gettext('Failed to decrypt Nginx UI directory: {0}'), + 4507: () => $gettext('Failed to decrypt Nginx directory: {0}'), + 4508: () => $gettext('Failed to verify hashes: {0}'), + 4509: () => $gettext('Failed to restore Nginx configs: {0}'), + 4510: () => $gettext('Failed to restore Nginx UI files: {0}'), + 4511: () => $gettext('Backup file not found: {0}'), + 4512: () => $gettext('Invalid security token format'), + 4513: () => $gettext('Invalid AES key format: {0}'), + 4514: () => $gettext('Invalid AES IV format: {0}'), + 4601: () => $gettext('Failed to open zip file: {0}'), + 4602: () => $gettext('Failed to create directory: {0}'), + 4603: () => $gettext('Failed to create parent directory: {0}'), + 4604: () => $gettext('Failed to create file: {0}'), + 4605: () => $gettext('Failed to open zip entry: {0}'), + 4701: () => $gettext('Failed to read encrypted file: {0}'), + 4702: () => $gettext('Failed to decrypt file: {0}'), + 4703: () => $gettext('Failed to write decrypted file: {0}'), + 4801: () => $gettext('Failed to read hash info file: {0}'), + 4802: () => $gettext('Failed to calculate Nginx UI hash: {0}'), + 4803: () => $gettext('Failed to calculate Nginx hash: {0}'), + 4804: () => $gettext('Hash verification failed: file integrity compromised'), +} diff --git a/app/src/language/ar/app.po b/app/src/language/ar/app.po index 474c8098..3f72f40c 100644 --- a/app/src/language/ar/app.po +++ b/app/src/language/ar/app.po @@ -21,15 +21,15 @@ msgstr "المصادقة الثنائية" msgid "2FA Settings" msgstr "إعدادات المصادقة الثنائية" -#: src/routes/index.ts:290 +#: src/routes/modules/system.ts:26 msgid "About" msgstr "عن" -#: src/routes/index.ts:210 src/views/site/ngx_conf/LogEntry.vue:75 +#: src/routes/modules/nginx_log.ts:17 src/views/site/ngx_conf/LogEntry.vue:75 msgid "Access Logs" msgstr "سجلات الدخول" -#: src/routes/index.ts:148 src/views/certificate/ACMEUser.vue:113 +#: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:113 #: src/views/certificate/ACMEUserSelector.vue:85 msgid "ACME User" msgstr "مستخدم ACME" @@ -41,7 +41,7 @@ msgstr "مستخدم ACME" #: src/views/environment/envColumns.tsx:97 #: src/views/notification/notificationColumns.tsx:65 #: src/views/preference/AuthSettings.vue:30 -#: src/views/site/site_category/columns.ts:29 +#: src/views/site/site_category/columns.ts:28 #: src/views/site/site_list/columns.tsx:76 src/views/stream/StreamList.vue:49 #: src/views/user/userColumns.tsx:60 msgid "Action" @@ -62,7 +62,7 @@ msgstr "إضافة" msgid "Add a passkey" msgstr "أضف مفتاح مرور" -#: src/routes/index.ts:118 src/views/config/ConfigEditor.vue:144 +#: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:144 #: src/views/config/ConfigEditor.vue:204 msgid "Add Configuration" msgstr "إضافة تكوين" @@ -76,7 +76,7 @@ msgstr "أضف التوجيه أدناه" msgid "Add Location" msgstr "أضف مكان" -#: src/routes/index.ts:63 src/views/site/SiteAdd.vue:89 +#: src/routes/modules/sites.ts:26 src/views/site/site_add/SiteAdd.vue:89 msgid "Add Site" msgstr "أضف موقع" @@ -252,6 +252,10 @@ msgstr "تم تعطيل التجديد التلقائي لـ‎%{name}" msgid "Auto-renewal enabled for %{name}" msgstr "تم تمكين التجديد التلقائي لـ‏%{name}" +#: src/views/system/Backup/SystemRestore.vue:92 +msgid "Automatic Restart" +msgstr "" + #: src/views/certificate/CertificateEditor.vue:255 #: src/views/config/ConfigEditor.vue:213 src/views/config/ConfigList.vue:106 #: src/views/config/ConfigList.vue:180 src/views/nginx_log/NginxLog.vue:173 @@ -268,6 +272,25 @@ msgstr "العودة إلى الصفحة الرئيسية" msgid "Back to list" msgstr "العودة إلى القائمة" +#: src/routes/modules/system.ts:33 +#, fuzzy +msgid "Backup" +msgstr "رجوع" + +#: src/views/system/Backup/SystemRestore.vue:100 +msgid "Backup file integrity check failed, it may have been tampered with" +msgstr "" + +#: src/constants/errors/backup.ts:39 +#, fuzzy +msgid "Backup file not found: {0}" +msgstr "لم يتم العثور على الملف" + +#: src/views/system/Backup/BackupCreator.vue:42 +#, fuzzy +msgid "Backup has been downloaded successfully" +msgstr "تم إعادة تحميل Nginx بنجاح" + #: src/views/preference/AuthSettings.vue:129 msgid "Ban Threshold Minutes" msgstr "دقائق حد الحظر" @@ -280,7 +303,7 @@ msgstr "عناوين IP المحظورة" msgid "Banned Until" msgstr "محظور حتى" -#: src/views/site/SiteAdd.vue:95 +#: src/views/site/site_add/SiteAdd.vue:95 msgid "Base information" msgstr "المعلومات الأساسية" @@ -397,12 +420,12 @@ msgstr[3] "حالة الشهادات" msgstr[4] "حالة الشهادات" msgstr[5] "حالة الشهادة" -#: src/routes/index.ts:139 +#: src/routes/modules/certificates.ts:11 #: src/views/certificate/CertificateList/Certificate.vue:13 msgid "Certificates" msgstr "شهادات" -#: src/routes/index.ts:156 +#: src/routes/modules/certificates.ts:28 msgid "Certificates List" msgstr "قائمة الشهادات" @@ -476,6 +499,10 @@ msgstr "مسح" msgid "Cleared successfully" msgstr "تم المسح بنجاح" +#: src/views/system/Backup/SystemRestore.vue:137 +msgid "Click or drag backup file to this area to upload" +msgstr "" + #: src/views/preference/components/TOTP.vue:110 msgid "Click to copy" msgstr "" @@ -491,6 +518,11 @@ msgstr "أمر" msgid "Comments" msgstr "تعليقات" +#: src/constants/errors/backup.ts:13 +#, fuzzy +msgid "Config path is empty" +msgstr "نماذج التكوين" + #: src/views/site/ngx_conf/config_template/ConfigTemplate.vue:84 msgid "Config Templates" msgstr "نماذج التكوين" @@ -499,7 +531,7 @@ msgstr "نماذج التكوين" msgid "Configuration file is test successful" msgstr "تم اختبار ملف التكوين بنجاح" -#: src/views/site/SiteAdd.vue:101 +#: src/views/site/site_add/SiteAdd.vue:101 msgid "Configuration Name" msgstr "اسم التكوين" @@ -507,7 +539,7 @@ msgstr "اسم التكوين" msgid "Configurations" msgstr "التكوينات" -#: src/views/site/SiteAdd.vue:96 +#: src/views/site/site_add/SiteAdd.vue:96 msgid "Configure SSL" msgstr "تكوين SSL" @@ -531,7 +563,13 @@ msgstr "محتوى" msgid "Copied" msgstr "تم النسخ" +#: src/views/system/Backup/BackupCreator.vue:128 +#, fuzzy +msgid "Copied!" +msgstr "تم النسخ" + #: src/components/SensitiveString/SensitiveString.vue:37 +#: src/views/system/Backup/BackupCreator.vue:128 msgid "Copy" msgstr "نسخ" @@ -556,10 +594,15 @@ msgstr "CPU:" msgid "Create" msgstr "إنشاء" -#: src/views/site/SiteAdd.vue:157 +#: src/views/site/site_add/SiteAdd.vue:157 msgid "Create Another" msgstr "إنشاء آخر" +#: src/views/system/Backup/BackupCreator.vue:86 +#, fuzzy +msgid "Create Backup" +msgstr "تم الإنشاء في" + #: src/views/config/ConfigList.vue:116 msgid "Create File" msgstr "إنشاء ملف" @@ -568,9 +611,15 @@ msgstr "إنشاء ملف" msgid "Create Folder" msgstr "إنشاء مجلد" +#: src/views/system/Backup/BackupCreator.vue:75 +msgid "" +"Create system backups including Nginx configuration and Nginx UI settings. " +"Backup files will be automatically downloaded to your computer." +msgstr "" + #: src/views/notification/notificationColumns.tsx:58 #: src/views/preference/components/Passkey.vue:95 -#: src/views/site/site_category/columns.ts:15 src/views/user/userColumns.tsx:48 +#: src/views/site/site_category/columns.ts:16 src/views/user/userColumns.tsx:48 msgid "Created at" msgstr "تم الإنشاء في" @@ -613,7 +662,7 @@ msgid "" "indicator." msgstr "قم بتخصيص اسم العقدة المحلية ليتم عرضها في مؤشر البيئة." -#: src/routes/index.ts:38 src/views/config/ConfigEditor.vue:134 +#: src/routes/modules/dashboard.ts:10 src/views/config/ConfigEditor.vue:134 #: src/views/config/ConfigEditor.vue:97 src/views/config/ConfigList.vue:64 msgid "Dashboard" msgstr "لوحة المعلومات" @@ -803,7 +852,8 @@ msgstr "تم التعطيل بنجاح" msgid "Disk IO" msgstr "إدخال/إخراج القرص" -#: src/routes/index.ts:184 src/views/certificate/DNSCredential.vue:40 +#: src/routes/modules/certificates.ts:56 +#: src/views/certificate/DNSCredential.vue:40 msgid "DNS Credentials" msgstr "بيانات اعتماد DNS" @@ -914,15 +964,15 @@ msgstr "تعديل %{n}" msgid "Edit %{n}" msgstr "تعديل %{n}" -#: src/routes/index.ts:128 src/views/config/ConfigEditor.vue:204 +#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:204 msgid "Edit Configuration" msgstr "تعديل التكوين" -#: src/routes/index.ts:78 +#: src/routes/modules/sites.ts:41 msgid "Edit Site" msgstr "تعديل الموقع" -#: src/routes/index.ts:98 +#: src/routes/modules/streams.ts:19 msgid "Edit Stream" msgstr "تعديل البث" @@ -947,7 +997,7 @@ msgstr "تم تفعيل المصادقة الثنائية بنجاح" msgid "Enable auto-renewal failed for %{name}" msgstr "فشل تفعيل التجديد التلقائي لـ %{name}" -#: src/views/site/SiteAdd.vue:43 +#: src/views/site/site_add/SiteAdd.vue:43 msgid "Enable failed" msgstr "فشل التفعيل" @@ -1010,8 +1060,9 @@ msgstr "تفعيل TOTP" msgid "Enabled" msgstr "مفعل" +#: src/views/site/site_add/SiteAdd.vue:40 #: src/views/site/site_edit/RightSettings.vue:33 -#: src/views/site/site_list/SiteList.vue:46 src/views/site/SiteAdd.vue:40 +#: src/views/site/site_list/SiteList.vue:46 #: src/views/stream/components/RightSettings.vue:29 #: src/views/stream/StreamList.vue:61 msgid "Enabled successfully" @@ -1025,7 +1076,8 @@ msgstr "تشفير الموقع باستخدام Let's Encrypt" msgid "Environment variables cleaned" msgstr "تم تنظيف متغيرات البيئة" -#: src/routes/index.ts:234 src/views/dashboard/Environments.vue:83 +#: src/routes/modules/environments.ts:11 +#: src/views/dashboard/Environments.vue:83 #: src/views/environment/Environment.vue:43 msgid "Environments" msgstr "البيئات" @@ -1035,7 +1087,7 @@ msgstr "البيئات" msgid "Error" msgstr "خطأ" -#: src/routes/index.ts:217 src/views/site/ngx_conf/LogEntry.vue:83 +#: src/routes/modules/nginx_log.ts:24 src/views/site/ngx_conf/LogEntry.vue:83 msgid "Error Logs" msgstr "سجلات الأخطاء" @@ -1060,11 +1112,131 @@ msgstr "تصدير" msgid "Fail to obtain certificate" msgstr "فشل في الحصول على الشهادة" +#: src/constants/errors/backup.ts:5 +#, fuzzy +msgid "Failed to backup Nginx config files: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:4 +msgid "Failed to backup Nginx UI files: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:17 +#, fuzzy +msgid "Failed to calculate hash: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:53 +msgid "Failed to calculate Nginx hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:52 +msgid "Failed to calculate Nginx UI hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:14 +msgid "Failed to copy config file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:15 +msgid "Failed to copy database directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:16 +#, fuzzy +msgid "Failed to copy database file: {0}" +msgstr "فشل في تعطيل %{msg}" + +#: src/constants/errors/backup.ts:30 +msgid "Failed to copy file content: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:19 +msgid "Failed to copy Nginx config directory: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:9 #, fuzzy msgid "Failed to create backup" msgstr "فشل في التفعيل %{msg}" +#: src/constants/errors/backup.ts:12 +#, fuzzy +msgid "Failed to create backup file: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:44 +#, fuzzy +msgid "Failed to create directory: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:46 +#, fuzzy +msgid "Failed to create file: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:6 +#, fuzzy +msgid "Failed to create hash info file: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:45 +#, fuzzy +msgid "Failed to create parent directory: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:32 +msgid "Failed to create restore directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:2 +#, fuzzy +msgid "Failed to create temporary directory" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:3 +#, fuzzy +msgid "Failed to create temporary subdirectory" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:9 +#, fuzzy +msgid "Failed to create zip archive: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:27 +#, fuzzy +msgid "Failed to create zip entry: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:26 +#, fuzzy +msgid "Failed to create zip file: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:29 +#, fuzzy +msgid "Failed to create zip header: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:24 +#, fuzzy +msgid "Failed to decrypt data: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:49 +#, fuzzy +msgid "Failed to decrypt file: {0}" +msgstr "فشل في تعطيل %{msg}" + +#: src/constants/errors/backup.ts:35 +msgid "Failed to decrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:34 +msgid "Failed to decrypt Nginx UI directory: {0}" +msgstr "" + #: src/views/site/site_edit/RightSettings.vue:45 #: src/views/site/site_list/SiteList.vue:60 #: src/views/stream/components/RightSettings.vue:41 @@ -1079,24 +1251,113 @@ msgstr "فشل في تعطيل %{msg}" msgid "Failed to enable %{msg}" msgstr "فشل في التفعيل %{msg}" +#: src/constants/errors/backup.ts:23 +#, fuzzy +msgid "Failed to encrypt data: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:21 +#, fuzzy +msgid "Failed to encrypt file: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:8 +msgid "Failed to encrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:7 +msgid "Failed to encrypt Nginx UI directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:33 +#, fuzzy +msgid "Failed to extract archive: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:10 +#, fuzzy +msgid "Failed to generate AES key: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:11 +#, fuzzy +msgid "Failed to generate initialization vector: {0}" +msgstr "فشل في الحصول على معلومات الشهادة" + #: src/language/constants.ts:5 msgid "Failed to get certificate information" msgstr "فشل في الحصول على معلومات الشهادة" +#: src/constants/errors/backup.ts:28 +#, fuzzy +msgid "Failed to open source file: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:47 +#, fuzzy +msgid "Failed to open zip entry: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:43 +#, fuzzy +msgid "Failed to open zip file: {0}" +msgstr "فشل في التفعيل %{msg}" + #: src/constants/errors/self_check.ts:4 msgid "Failed to parse nginx.conf" msgstr "" +#: src/constants/errors/backup.ts:48 +#, fuzzy +msgid "Failed to read encrypted file: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:20 +#, fuzzy +msgid "Failed to read file: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:51 +#, fuzzy +msgid "Failed to read hash info file: {0}" +msgstr "فشل في التفعيل %{msg}" + #: src/constants/errors/self_check.ts:3 #, fuzzy msgid "Failed to read nginx.conf" msgstr "فشل في التفعيل %{msg}" +#: src/constants/errors/backup.ts:37 +#, fuzzy +msgid "Failed to restore Nginx configs: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:38 +msgid "Failed to restore Nginx UI files: {0}" +msgstr "" + #: src/views/site/site_edit/SiteEdit.vue:135 #: src/views/stream/StreamEdit.vue:122 msgid "Failed to save, syntax error(s) was detected in the configuration." msgstr "فشل في الحفظ، تم اكتشاف خطأ(أخطاء) في بناء الجملة في التكوين." +#: src/constants/errors/backup.ts:36 +#, fuzzy +msgid "Failed to verify hashes: {0}" +msgstr "فشل في التفعيل %{msg}" + +#: src/constants/errors/backup.ts:50 +msgid "Failed to write decrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:22 +msgid "Failed to write encrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:31 +msgid "Failed to write to zip buffer: {0}" +msgstr "" + #: src/language/constants.ts:32 msgid "File exists" msgstr "الملف موجود" @@ -1113,7 +1374,7 @@ msgstr "" msgid "Filter" msgstr "تصفيه" -#: src/language/constants.ts:19 src/views/site/SiteAdd.vue:97 +#: src/language/constants.ts:19 src/views/site/site_add/SiteAdd.vue:97 msgid "Finished" msgstr "انتهى" @@ -1188,11 +1449,15 @@ msgstr "جارٍ الحصول على الشهادة، يرجى الانتظار. msgid "Github Proxy" msgstr "وكيل Github" +#: src/constants/errors/backup.ts:54 +msgid "Hash verification failed: file integrity compromised" +msgstr "" + #: src/components/SensitiveString/SensitiveString.vue:40 msgid "Hide" msgstr "إخفاء" -#: src/routes/index.ts:30 +#: src/routes/index.ts:47 msgid "Home" msgstr "الصفحة الرئيسية" @@ -1244,7 +1509,8 @@ msgstr "" msgid "Import" msgstr "استيراد" -#: src/routes/index.ts:174 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:46 +#: src/views/certificate/CertificateEditor.vue:85 msgid "Import Certificate" msgstr "استيراد شهادة" @@ -1269,7 +1535,7 @@ msgstr "أدخل الرمز من التطبيق:" msgid "Input the recovery code:" msgstr "أدخل رمز الاسترداد:" -#: src/routes/index.ts:312 src/views/other/Install.vue:134 +#: src/routes/modules/auth.ts:8 src/views/other/Install.vue:134 msgid "Install" msgstr "تثبيت" @@ -1285,6 +1551,21 @@ msgstr "فترة" msgid "Invalid" msgstr "غير صالح" +#: src/constants/errors/backup.ts:42 +#, fuzzy +msgid "Invalid AES IV format: {0}" +msgstr "رمز 2FA أو الاسترداد غير صالح" + +#: src/constants/errors/backup.ts:41 +#, fuzzy +msgid "Invalid AES key format: {0}" +msgstr "رمز 2FA أو الاسترداد غير صالح" + +#: src/views/system/Backup/SystemRestore.vue:67 +#, fuzzy +msgid "Invalid file object" +msgstr "اسم ملف غير صالح" + #: src/views/config/components/Rename.vue:64 #: src/views/config/ConfigEditor.vue:250 msgid "Invalid filename" @@ -1299,6 +1580,10 @@ msgstr "اسم المجلد غير صالح" msgid "Invalid otp code" msgstr "رمز 2FA أو الاسترداد غير صالح" +#: src/constants/errors/backup.ts:25 +msgid "Invalid padding in decrypted data" +msgstr "" + #: src/components/TwoFA/use2FAModal.ts:61 msgid "Invalid passcode or recovery code" msgstr "رمز المرور أو رمز الاسترداد غير صالح" @@ -1313,6 +1598,11 @@ msgstr "رمز 2FA أو الاسترداد غير صالح" msgid "Invalid request format" msgstr "رمز 2FA أو الاسترداد غير صالح" +#: src/constants/errors/backup.ts:40 +#, fuzzy +msgid "Invalid security token format" +msgstr "رمز 2FA أو الاسترداد غير صالح" + #: src/views/preference/AuthSettings.vue:18 msgid "IP" msgstr "IP" @@ -1427,7 +1717,7 @@ msgstr "أماكن" msgid "Log" msgstr "سجل" -#: src/routes/index.ts:318 src/views/other/Login.vue:222 +#: src/routes/modules/auth.ts:14 src/views/other/Login.vue:222 msgid "Login" msgstr "تسجيل الدخول" @@ -1467,20 +1757,20 @@ msgstr "" "تأكد من تكوين وكيل عكسي لدليل .well-known إلى HTTPChallengePort قبل الحصول " "على الشهادة." -#: src/routes/index.ts:108 src/views/config/ConfigEditor.vue:102 +#: src/routes/modules/config.ts:10 src/views/config/ConfigEditor.vue:102 #: src/views/config/ConfigEditor.vue:139 src/views/config/ConfigList.vue:69 msgid "Manage Configs" msgstr "إدارة التكوينات" -#: src/routes/index.ts:47 src/views/site/site_list/SiteList.vue:94 +#: src/routes/modules/sites.ts:10 src/views/site/site_list/SiteList.vue:94 msgid "Manage Sites" msgstr "إدارة المواقع" -#: src/routes/index.ts:89 src/views/stream/StreamList.vue:119 +#: src/routes/modules/streams.ts:10 src/views/stream/StreamList.vue:119 msgid "Manage Streams" msgstr "إدارة التدفقات" -#: src/routes/index.ts:257 src/views/user/User.vue:10 +#: src/routes/modules/user.ts:10 src/views/user/User.vue:10 msgid "Manage Users" msgstr "إدارة المستخدمين" @@ -1516,11 +1806,12 @@ msgstr "نموذج" msgid "Modify" msgstr "تعديل" -#: src/routes/index.ts:164 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:36 +#: src/views/certificate/CertificateEditor.vue:85 msgid "Modify Certificate" msgstr "تعديل الشهادة" -#: src/views/site/SiteAdd.vue:154 +#: src/views/site/site_add/SiteAdd.vue:154 msgid "Modify Config" msgstr "تعديل التكوين" @@ -1581,7 +1872,7 @@ msgstr "تم إصدار نسخة جديدة" #: src/views/certificate/WildcardCertificate.vue:91 #: src/views/site/cert/components/ObtainCert.vue:211 -#: src/views/site/SiteAdd.vue:141 +#: src/views/site/site_add/SiteAdd.vue:141 msgid "Next" msgstr "التالي" @@ -1617,6 +1908,16 @@ msgstr "" msgid "Nginx conf not include stream-enabled" msgstr "" +#: src/constants/errors/backup.ts:18 +#, fuzzy +msgid "Nginx config directory is not set" +msgstr "قائمة السماح لمجلد سجلات Nginx" + +#: src/views/system/Backup/SystemRestore.vue:84 +#, fuzzy +msgid "Nginx configuration has been restored" +msgstr "خطأ في تحليل تكوين Nginx" + #: src/views/site/site_edit/SiteEdit.vue:223 #: src/views/stream/StreamEdit.vue:208 msgid "Nginx Configuration Parse Error" @@ -1638,7 +1939,7 @@ msgstr "مسار سجل أخطاء Nginx" msgid "Nginx is not running" msgstr "Nginx لا يعمل" -#: src/routes/index.ts:202 src/views/nginx_log/NginxLog.vue:148 +#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:148 msgid "Nginx Log" msgstr "سجل Nginx" @@ -1666,6 +1967,18 @@ msgstr "أمر إعادة تشغيل Nginx" msgid "Nginx restarted successfully" msgstr "تم إعادة تشغيل Nginx بنجاح" +#: src/views/system/Backup/SystemRestore.vue:88 +#, fuzzy +msgid "Nginx UI configuration has been restored" +msgstr "خطأ في تحليل تكوين Nginx" + +#: src/views/system/Backup/SystemRestore.vue:93 +#, fuzzy +msgid "" +"Nginx UI configuration has been restored and will restart automatically in a " +"few seconds." +msgstr "خطأ في تحليل تكوين Nginx" + #: src/components/ChatGPT/ChatGPT.vue:374 #: src/components/Notification/Notification.vue:133 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:63 @@ -1695,7 +2008,7 @@ msgstr "سر العقدة" msgid "Not After" msgstr "ليس بعد" -#: src/routes/index.ts:324 +#: src/routes/modules/error.ts:8 msgid "Not Found" msgstr "غير موجود" @@ -1720,7 +2033,8 @@ msgstr "" msgid "Notification" msgstr "إشعار" -#: src/components/Notification/Notification.vue:131 src/routes/index.ts:248 +#: src/components/Notification/Notification.vue:131 +#: src/routes/modules/notifications.ts:10 msgid "Notifications" msgstr "الإشعارات" @@ -1770,6 +2084,8 @@ msgstr "حسنًا" #: src/views/site/site_list/SiteList.vue:144 #: src/views/stream/components/RightSettings.vue:50 #: src/views/stream/StreamList.vue:164 +#: src/views/system/Backup/BackupCreator.vue:149 +#: src/views/system/Backup/SystemRestore.vue:94 msgid "OK" msgstr "حسنًا" @@ -1784,6 +2100,10 @@ msgstr "بمجرد اكتمال التحقق، سيتم إزالة السجلا msgid "Online" msgstr "متصل" +#: src/views/system/Backup/SystemRestore.vue:24 +msgid "Only zip files are allowed" +msgstr "" + #: src/views/preference/Preference.vue:170 msgid "OpenAI" msgstr "أوبن أي آي" @@ -1897,6 +2217,15 @@ msgstr "" msgid "Please enter the OTP code:" msgstr "يرجى إدخال رمز OTP:" +#: src/views/system/Backup/SystemRestore.vue:58 +#, fuzzy +msgid "Please enter the security token" +msgstr "يرجى إدخال رمز OTP:" + +#: src/views/system/Backup/SystemRestore.vue:153 +msgid "Please enter the security token received during backup" +msgstr "" + #: src/views/certificate/DNSCredential.vue:53 msgid "" "Please fill in the API authentication credentials provided by your DNS " @@ -1960,6 +2289,15 @@ msgid "" "Please note that the unit of time configurations below are all in seconds." msgstr "يرجى ملاحظة أن تكوين وحدات الوقت أدناه كلها بالثواني." +#: src/views/system/Backup/BackupCreator.vue:107 +msgid "Please save this security token, you will need it for restoration:" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:53 +#, fuzzy +msgid "Please select a backup file" +msgstr "يرجى اختيار عقدة واحدة على الأقل!" + #: src/views/environment/Environment.vue:58 msgid "Please select at least one node to upgrade" msgstr "يرجى اختيار عقدة واحدة على الأقل للترقية" @@ -1970,7 +2308,7 @@ msgstr "يرجى اختيار عقدة واحدة على الأقل للترقي msgid "Pre-release" msgstr "ما قبل الإصدار" -#: src/routes/index.ts:266 src/views/preference/Preference.vue:141 +#: src/routes/modules/preference.ts:10 src/views/preference/Preference.vue:141 msgid "Preference" msgstr "تفضيل" @@ -2232,6 +2570,21 @@ msgstr "إعادة تشغيل" msgid "Restarting" msgstr "إعادة التشغيل" +#: src/views/system/Backup/SystemRestore.vue:81 +#, fuzzy +msgid "Restore completed successfully" +msgstr "تم الحذف بنجاح" + +#: src/views/system/Backup/SystemRestore.vue:165 +#, fuzzy +msgid "Restore Nginx Configuration" +msgstr "مجلد تكوينات Nginx" + +#: src/views/system/Backup/SystemRestore.vue:176 +#, fuzzy +msgid "Restore Nginx UI Configuration" +msgstr "مجلد تكوينات Nginx" + #: src/views/preference/AuthSettings.vue:107 msgid "RP Display Name" msgstr "اسم العرض RP" @@ -2274,7 +2627,7 @@ msgstr "حفظ التوجيه" #: src/views/config/ConfigEditor.vue:171 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:41 -#: src/views/site/SiteAdd.vue:46 +#: src/views/site/site_add/SiteAdd.vue:46 msgid "Save error %{msg}" msgstr "خطأ في الحفظ %{msg}" @@ -2325,7 +2678,8 @@ msgstr "تم الحفظ بنجاح" #: src/views/config/ConfigEditor.vue:167 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:39 -#: src/views/site/site_edit/SiteEdit.vue:152 src/views/site/SiteAdd.vue:37 +#: src/views/site/site_add/SiteAdd.vue:37 +#: src/views/site/site_edit/SiteEdit.vue:152 #: src/views/stream/StreamEdit.vue:139 msgid "Saved successfully" msgstr "تم الحفظ بنجاح" @@ -2342,11 +2696,20 @@ msgstr "حزمة تطوير البرمجيات SDK" msgid "Secret has been copied" msgstr "تم نسخ السر" +#: src/views/system/Backup/SystemRestore.vue:150 +msgid "Security Token" +msgstr "" + +#: src/views/system/Backup/BackupCreator.vue:94 +#, fuzzy +msgid "Security Token Information" +msgstr "رمز 2FA أو الاسترداد غير صالح" + #: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:189 msgid "Selector" msgstr "المحدد" -#: src/routes/index.ts:283 src/views/system/SelfCheck/SelfCheck.vue:42 +#: src/routes/modules/system.ts:19 src/views/system/SelfCheck/SelfCheck.vue:42 msgid "Self Check" msgstr "" @@ -2416,11 +2779,12 @@ msgstr "تسجيل الدخول باستخدام مفتاح المرور" msgid "Single Directive" msgstr "توجيه واحد" -#: src/routes/index.ts:71 src/views/site/site_category/SiteCategory.vue:10 +#: src/routes/modules/sites.ts:34 +#: src/views/site/site_category/SiteCategory.vue:10 msgid "Site Categories" msgstr "فئات الموقع" -#: src/views/site/SiteAdd.vue:147 +#: src/views/site/site_add/SiteAdd.vue:147 #, fuzzy msgid "Site Config Created Successfully" msgstr "تم إنشاء تكوين النطاق بنجاح" @@ -2430,7 +2794,7 @@ msgstr "تم إنشاء تكوين النطاق بنجاح" msgid "Site is enabled" msgstr "معطل" -#: src/routes/index.ts:224 +#: src/routes/modules/nginx_log.ts:31 msgid "Site Logs" msgstr "سجلات الموقع" @@ -2444,7 +2808,7 @@ msgstr "لم يتم العثور على الملف" msgid "Sites Directory" msgstr "مجلد" -#: src/routes/index.ts:56 +#: src/routes/modules/sites.ts:19 msgid "Sites List" msgstr "قائمة المواقع" @@ -2484,6 +2848,10 @@ msgstr "تسجيل الدخول عبر SSO" msgid "Stable" msgstr "مستقر" +#: src/views/system/Backup/SystemRestore.vue:187 +msgid "Start Restore" +msgstr "" + #: src/views/certificate/ACMEUser.vue:65 #: src/views/certificate/CertificateList/certColumns.tsx:68 #: src/views/environment/envColumns.tsx:44 @@ -2537,6 +2905,10 @@ msgid "" "guide/nginx-proxy-example.html" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:140 +msgid "Supported file type: .zip" +msgstr "" + #: src/views/dashboard/ServerAnalytic.vue:236 #: src/views/dashboard/ServerAnalytic.vue:237 msgid "Swap" @@ -2594,7 +2966,7 @@ msgstr "خطأ في تزامن التكوين" msgid "Sync Config Success" msgstr "تمت مزامنة التكوين بنجاح" -#: src/views/site/site_category/SiteCategory.vue:17 +#: src/views/site/site_category/SiteCategory.vue:18 msgid "Sync Nodes" msgstr "مزامنة العقد" @@ -2611,20 +2983,30 @@ msgstr "مزامنة إلى" msgid "Synchronization" msgstr "مزامنة" -#: src/routes/index.ts:275 +#: src/routes/modules/system.ts:11 msgid "System" msgstr "نظام" +#: src/views/system/Backup/BackupCreator.vue:71 +#, fuzzy +msgid "System Backup" +msgstr "نظام" + #: src/views/certificate/ACMEUserSelector.vue:88 msgid "System Initial User" msgstr "مستخدم النظام الأولي" +#: src/views/system/Backup/SystemRestore.vue:117 +#, fuzzy +msgid "System Restore" +msgstr "نظام" + #: src/constants/errors/self_check.ts:2 #, fuzzy msgid "Task not found" msgstr "غير موجود" -#: src/routes/index.ts:194 src/views/terminal/Terminal.vue:114 +#: src/routes/modules/terminal.ts:10 src/views/terminal/Terminal.vue:114 msgid "Terminal" msgstr "محطة" @@ -2683,7 +3065,7 @@ msgstr "" "يجب أن يحتوي اسم العقدة على حروف وأحرف يونيكود وأرقام وشرطات وعلامات وصل " "ونقاط فقط." -#: src/views/site/SiteAdd.vue:120 +#: src/views/site/site_add/SiteAdd.vue:120 #, fuzzy msgid "The parameter of server_name is required" msgstr "عامل server_name مطلوب" @@ -2775,10 +3157,28 @@ msgid "" "This field should only contain letters, unicode characters, numbers, and -_." msgstr "يجب أن يحتوي هذا الحقل على حروف وأحرف يونيكود وأرقام و-_. فقط." +#: src/views/system/Backup/BackupCreator.vue:141 +msgid "" +"This token will only be shown once and cannot be retrieved later. Please " +"make sure to save it in a secure location." +msgstr "" + #: src/constants/form_errors.ts:4 msgid "This value is already taken" msgstr "هذه القيمة مستخدمة مسبقا" +#: src/views/system/Backup/SystemRestore.vue:169 +msgid "" +"This will restore all Nginx configuration files. Nginx will restart after " +"the restoration is complete." +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:180 +msgid "" +"This will restore configuration files and database. Nginx UI will restart " +"after the restoration is complete." +msgstr "" + #: src/views/environment/BatchUpgrader.vue:182 msgid "" "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}." @@ -2896,7 +3296,7 @@ msgstr "محدث في" msgid "Updated successfully" msgstr "تم التحديث بنجاح" -#: src/routes/index.ts:297 src/views/environment/Environment.vue:66 +#: src/routes/modules/system.ts:40 src/views/environment/Environment.vue:66 #: src/views/system/Upgrade.vue:143 src/views/system/Upgrade.vue:226 msgid "Upgrade" msgstr "ترقية" @@ -2960,6 +3360,10 @@ msgstr "اسم المستخدم (*)" msgid "Valid" msgstr "صالح" +#: src/views/system/Backup/SystemRestore.vue:159 +msgid "Verify Backup File Integrity" +msgstr "" + #: src/views/environment/envColumns.tsx:31 msgid "Version" msgstr "إصدار" @@ -2994,10 +3398,18 @@ msgstr "عرض" #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33 #: src/views/notification/notificationColumns.tsx:22 #: src/views/preference/components/AddPasskey.vue:82 -#: src/views/site/SiteAdd.vue:115 +#: src/views/site/site_add/SiteAdd.vue:115 +#: src/views/system/Backup/BackupCreator.vue:138 msgid "Warning" msgstr "تحذير" +#: src/views/system/Backup/SystemRestore.vue:121 +msgid "" +"Warning: Restore operation will overwrite current configurations. Make sure " +"you have a valid backup file and security token, and carefully select what " +"to restore." +msgstr "" + #: src/views/certificate/DNSCredential.vue:56 msgid "" "We will add one or more TXT records to the DNS records of your domain for " @@ -3102,6 +3514,10 @@ msgstr "" msgid "Your passkeys" msgstr "مفاتيح المرور الخاصة بك" +#, fuzzy +#~ msgid "Restart Required" +#~ msgstr "إعادة التشغيل" + #~ msgid "Deploy %{conf_name} to %{node_name} successfully" #~ msgstr "تم نشر %{conf_name} إلى %{node_name} بنجاح" @@ -3138,9 +3554,6 @@ msgstr "مفاتيح المرور الخاصة بك" #~ msgid "Enable successfully" #~ msgstr "تم التفعيل بنجاح" -#~ msgid "Please select at least one node!" -#~ msgstr "يرجى اختيار عقدة واحدة على الأقل!" - #~ msgid "Please upgrade the remote Nginx UI to the latest version" #~ msgstr "يرجى ترقية واجهة Nginx البعيدة إلى أحدث إصدار" diff --git a/app/src/language/de_DE/app.po b/app/src/language/de_DE/app.po index 23b540ed..a7177809 100644 --- a/app/src/language/de_DE/app.po +++ b/app/src/language/de_DE/app.po @@ -17,15 +17,15 @@ msgstr "2FA" msgid "2FA Settings" msgstr "2FA-Einstellungen" -#: src/routes/index.ts:290 +#: src/routes/modules/system.ts:26 msgid "About" msgstr "Über" -#: src/routes/index.ts:210 src/views/site/ngx_conf/LogEntry.vue:75 +#: src/routes/modules/nginx_log.ts:17 src/views/site/ngx_conf/LogEntry.vue:75 msgid "Access Logs" msgstr "Zugriffslog" -#: src/routes/index.ts:148 src/views/certificate/ACMEUser.vue:113 +#: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:113 #: src/views/certificate/ACMEUserSelector.vue:85 #, fuzzy msgid "ACME User" @@ -38,7 +38,7 @@ msgstr "Benutzername" #: src/views/environment/envColumns.tsx:97 #: src/views/notification/notificationColumns.tsx:65 #: src/views/preference/AuthSettings.vue:30 -#: src/views/site/site_category/columns.ts:29 +#: src/views/site/site_category/columns.ts:28 #: src/views/site/site_list/columns.tsx:76 src/views/stream/StreamList.vue:49 #: src/views/user/userColumns.tsx:60 msgid "Action" @@ -59,7 +59,7 @@ msgstr "Hinzufügen" msgid "Add a passkey" msgstr "Passkey hinzufügen" -#: src/routes/index.ts:118 src/views/config/ConfigEditor.vue:144 +#: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:144 #: src/views/config/ConfigEditor.vue:204 #, fuzzy msgid "Add Configuration" @@ -74,7 +74,7 @@ msgstr "Anweisung darunter hinzufügen" msgid "Add Location" msgstr "Ort hinzufügen" -#: src/routes/index.ts:63 src/views/site/SiteAdd.vue:89 +#: src/routes/modules/sites.ts:26 src/views/site/site_add/SiteAdd.vue:89 msgid "Add Site" msgstr "Seite hinzufügen" @@ -265,6 +265,10 @@ msgstr "Automatische Verlängerung deaktiviert für %{name}" msgid "Auto-renewal enabled for %{name}" msgstr "Automatische Verlängerung aktiviert für %{name}" +#: src/views/system/Backup/SystemRestore.vue:92 +msgid "Automatic Restart" +msgstr "" + #: src/views/certificate/CertificateEditor.vue:255 #: src/views/config/ConfigEditor.vue:213 src/views/config/ConfigList.vue:106 #: src/views/config/ConfigList.vue:180 src/views/nginx_log/NginxLog.vue:173 @@ -282,6 +286,25 @@ msgstr "Zurück" msgid "Back to list" msgstr "Zurück zur Liste" +#: src/routes/modules/system.ts:33 +#, fuzzy +msgid "Backup" +msgstr "Zurück" + +#: src/views/system/Backup/SystemRestore.vue:100 +msgid "Backup file integrity check failed, it may have been tampered with" +msgstr "" + +#: src/constants/errors/backup.ts:39 +#, fuzzy +msgid "Backup file not found: {0}" +msgstr "File Not Found" + +#: src/views/system/Backup/BackupCreator.vue:42 +#, fuzzy +msgid "Backup has been downloaded successfully" +msgstr "Speichern erfolgreich" + #: src/views/preference/AuthSettings.vue:129 msgid "Ban Threshold Minutes" msgstr "Schwellenwert für Minuten sperren" @@ -294,7 +317,7 @@ msgstr "Gesperrte IPs" msgid "Banned Until" msgstr "Gesperrt bis" -#: src/views/site/SiteAdd.vue:95 +#: src/views/site/site_add/SiteAdd.vue:95 msgid "Base information" msgstr "Basisinformationen" @@ -412,13 +435,13 @@ msgid_plural "Certificates Status" msgstr[0] "Zertifikatsstatus" msgstr[1] "Zertifikatsstatus" -#: src/routes/index.ts:139 +#: src/routes/modules/certificates.ts:11 #: src/views/certificate/CertificateList/Certificate.vue:13 #, fuzzy msgid "Certificates" msgstr "Zertifikatsstatus" -#: src/routes/index.ts:156 +#: src/routes/modules/certificates.ts:28 #, fuzzy msgid "Certificates List" msgstr "Zertifikat ist gültig" @@ -493,6 +516,10 @@ msgstr "Säubern" msgid "Cleared successfully" msgstr "Erfolgreich deaktiviert" +#: src/views/system/Backup/SystemRestore.vue:137 +msgid "Click or drag backup file to this area to upload" +msgstr "" + #: src/views/preference/components/TOTP.vue:110 msgid "Click to copy" msgstr "" @@ -509,6 +536,11 @@ msgstr "Kommando" msgid "Comments" msgstr "Kom" +#: src/constants/errors/backup.ts:13 +#, fuzzy +msgid "Config path is empty" +msgstr "Konfigurationen" + #: src/views/site/ngx_conf/config_template/ConfigTemplate.vue:84 #, fuzzy msgid "Config Templates" @@ -518,7 +550,7 @@ msgstr "Konfigurationen" msgid "Configuration file is test successful" msgstr "Konfigurationsdatei erfolgreich getestet" -#: src/views/site/SiteAdd.vue:101 +#: src/views/site/site_add/SiteAdd.vue:101 msgid "Configuration Name" msgstr "Konf" @@ -526,7 +558,7 @@ msgstr "Konf" msgid "Configurations" msgstr "Konfigurationen" -#: src/views/site/SiteAdd.vue:96 +#: src/views/site/site_add/SiteAdd.vue:96 msgid "Configure SSL" msgstr "SSL konfigurieren" @@ -550,7 +582,13 @@ msgstr "Inhalt" msgid "Copied" msgstr "Kopiert" +#: src/views/system/Backup/BackupCreator.vue:128 +#, fuzzy +msgid "Copied!" +msgstr "Kopiert" + #: src/components/SensitiveString/SensitiveString.vue:37 +#: src/views/system/Backup/BackupCreator.vue:128 msgid "Copy" msgstr "Kopieren" @@ -576,10 +614,15 @@ msgstr "CPU:" msgid "Create" msgstr "Erstellt" -#: src/views/site/SiteAdd.vue:157 +#: src/views/site/site_add/SiteAdd.vue:157 msgid "Create Another" msgstr "Weiteres erstellen" +#: src/views/system/Backup/BackupCreator.vue:86 +#, fuzzy +msgid "Create Backup" +msgstr "Erstellt" + #: src/views/config/ConfigList.vue:116 #, fuzzy msgid "Create File" @@ -590,9 +633,15 @@ msgstr "Erstellt" msgid "Create Folder" msgstr "Weiteres erstellen" +#: src/views/system/Backup/BackupCreator.vue:75 +msgid "" +"Create system backups including Nginx configuration and Nginx UI settings. " +"Backup files will be automatically downloaded to your computer." +msgstr "" + #: src/views/notification/notificationColumns.tsx:58 #: src/views/preference/components/Passkey.vue:95 -#: src/views/site/site_category/columns.ts:15 src/views/user/userColumns.tsx:48 +#: src/views/site/site_category/columns.ts:16 src/views/user/userColumns.tsx:48 msgid "Created at" msgstr "Erstellt" @@ -637,7 +686,7 @@ msgid "" msgstr "" "Name des lokalen Knotens anpassen, der im Umgebungsindikator angezeigt wird." -#: src/routes/index.ts:38 src/views/config/ConfigEditor.vue:134 +#: src/routes/modules/dashboard.ts:10 src/views/config/ConfigEditor.vue:134 #: src/views/config/ConfigEditor.vue:97 src/views/config/ConfigList.vue:64 msgid "Dashboard" msgstr "Übersicht" @@ -833,7 +882,8 @@ msgstr "Erfolgreich deaktiviert" msgid "Disk IO" msgstr "Festplatten-IO" -#: src/routes/index.ts:184 src/views/certificate/DNSCredential.vue:40 +#: src/routes/modules/certificates.ts:56 +#: src/views/certificate/DNSCredential.vue:40 msgid "DNS Credentials" msgstr "DNS-Zugangsdaten" @@ -953,15 +1003,15 @@ msgstr "Bearbeiten %{n}" msgid "Edit %{n}" msgstr "Bearbeiten %{n}" -#: src/routes/index.ts:128 src/views/config/ConfigEditor.vue:204 +#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:204 msgid "Edit Configuration" msgstr "Konfiguration bearbeiten" -#: src/routes/index.ts:78 +#: src/routes/modules/sites.ts:41 msgid "Edit Site" msgstr "Seite bearbeiten" -#: src/routes/index.ts:98 +#: src/routes/modules/streams.ts:19 #, fuzzy msgid "Edit Stream" msgstr "Seite bearbeiten" @@ -990,7 +1040,7 @@ msgstr "Aktivieren erfolgreich" msgid "Enable auto-renewal failed for %{name}" msgstr "Aktiviere automatische Verlängerung fehlgeschlagen für %{name}" -#: src/views/site/SiteAdd.vue:43 +#: src/views/site/site_add/SiteAdd.vue:43 msgid "Enable failed" msgstr "Aktivieren fehlgeschlagen" @@ -1056,8 +1106,9 @@ msgstr "Aktiviere TLS" msgid "Enabled" msgstr "Aktiviert" +#: src/views/site/site_add/SiteAdd.vue:40 #: src/views/site/site_edit/RightSettings.vue:33 -#: src/views/site/site_list/SiteList.vue:46 src/views/site/SiteAdd.vue:40 +#: src/views/site/site_list/SiteList.vue:46 #: src/views/stream/components/RightSettings.vue:29 #: src/views/stream/StreamList.vue:61 msgid "Enabled successfully" @@ -1071,7 +1122,8 @@ msgstr "Webseite mit Let's Encrypt verschlüsseln" msgid "Environment variables cleaned" msgstr "Umgebungsvariablen gesäubert" -#: src/routes/index.ts:234 src/views/dashboard/Environments.vue:83 +#: src/routes/modules/environments.ts:11 +#: src/views/dashboard/Environments.vue:83 #: src/views/environment/Environment.vue:43 #, fuzzy msgid "Environments" @@ -1082,7 +1134,7 @@ msgstr "Kommentare" msgid "Error" msgstr "Fehler" -#: src/routes/index.ts:217 src/views/site/ngx_conf/LogEntry.vue:83 +#: src/routes/modules/nginx_log.ts:24 src/views/site/ngx_conf/LogEntry.vue:83 msgid "Error Logs" msgstr "Feherlogs" @@ -1109,11 +1161,130 @@ msgstr "Exportieren" msgid "Fail to obtain certificate" msgstr "Zertifikat ist gültig" +#: src/constants/errors/backup.ts:5 +msgid "Failed to backup Nginx config files: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:4 +msgid "Failed to backup Nginx UI files: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:17 +#, fuzzy +msgid "Failed to calculate hash: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:53 +msgid "Failed to calculate Nginx hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:52 +msgid "Failed to calculate Nginx UI hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:14 +msgid "Failed to copy config file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:15 +msgid "Failed to copy database directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:16 +#, fuzzy +msgid "Failed to copy database file: {0}" +msgstr "Deaktivierung von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:30 +msgid "Failed to copy file content: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:19 +msgid "Failed to copy Nginx config directory: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:9 #, fuzzy msgid "Failed to create backup" msgstr "Aktiviern von %{msg} fehlgeschlagen" +#: src/constants/errors/backup.ts:12 +#, fuzzy +msgid "Failed to create backup file: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:44 +#, fuzzy +msgid "Failed to create directory: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:46 +#, fuzzy +msgid "Failed to create file: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:6 +#, fuzzy +msgid "Failed to create hash info file: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:45 +#, fuzzy +msgid "Failed to create parent directory: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:32 +msgid "Failed to create restore directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:2 +#, fuzzy +msgid "Failed to create temporary directory" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:3 +#, fuzzy +msgid "Failed to create temporary subdirectory" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:9 +#, fuzzy +msgid "Failed to create zip archive: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:27 +#, fuzzy +msgid "Failed to create zip entry: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:26 +#, fuzzy +msgid "Failed to create zip file: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:29 +#, fuzzy +msgid "Failed to create zip header: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:24 +#, fuzzy +msgid "Failed to decrypt data: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:49 +#, fuzzy +msgid "Failed to decrypt file: {0}" +msgstr "Deaktivierung von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:35 +msgid "Failed to decrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:34 +msgid "Failed to decrypt Nginx UI directory: {0}" +msgstr "" + #: src/views/site/site_edit/RightSettings.vue:45 #: src/views/site/site_list/SiteList.vue:60 #: src/views/stream/components/RightSettings.vue:41 @@ -1128,24 +1299,110 @@ msgstr "Deaktivierung von %{msg} fehlgeschlagen" msgid "Failed to enable %{msg}" msgstr "Aktiviern von %{msg} fehlgeschlagen" +#: src/constants/errors/backup.ts:23 +#, fuzzy +msgid "Failed to encrypt data: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:21 +#, fuzzy +msgid "Failed to encrypt file: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:8 +msgid "Failed to encrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:7 +msgid "Failed to encrypt Nginx UI directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:33 +#, fuzzy +msgid "Failed to extract archive: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:10 +#, fuzzy +msgid "Failed to generate AES key: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:11 +#, fuzzy +msgid "Failed to generate initialization vector: {0}" +msgstr "Fehler beim Abrufen von Zertifikatsinformationen" + #: src/language/constants.ts:5 msgid "Failed to get certificate information" msgstr "Fehler beim Abrufen von Zertifikatsinformationen" +#: src/constants/errors/backup.ts:28 +#, fuzzy +msgid "Failed to open source file: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:47 +#, fuzzy +msgid "Failed to open zip entry: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:43 +#, fuzzy +msgid "Failed to open zip file: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + #: src/constants/errors/self_check.ts:4 msgid "Failed to parse nginx.conf" msgstr "" +#: src/constants/errors/backup.ts:48 +msgid "Failed to read encrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:20 +#, fuzzy +msgid "Failed to read file: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:51 +msgid "Failed to read hash info file: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:3 msgid "Failed to read nginx.conf" msgstr "" +#: src/constants/errors/backup.ts:37 +msgid "Failed to restore Nginx configs: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:38 +msgid "Failed to restore Nginx UI files: {0}" +msgstr "" + #: src/views/site/site_edit/SiteEdit.vue:135 #: src/views/stream/StreamEdit.vue:122 msgid "Failed to save, syntax error(s) was detected in the configuration." msgstr "" "Fehler beim Speichern, Syntaxfehler wurden in der Konfiguration erkannt." +#: src/constants/errors/backup.ts:36 +#, fuzzy +msgid "Failed to verify hashes: {0}" +msgstr "Aktiviern von %{msg} fehlgeschlagen" + +#: src/constants/errors/backup.ts:50 +msgid "Failed to write decrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:22 +msgid "Failed to write encrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:31 +msgid "Failed to write to zip buffer: {0}" +msgstr "" + #: src/language/constants.ts:32 msgid "File exists" msgstr "Datei existiert" @@ -1162,7 +1419,7 @@ msgstr "" msgid "Filter" msgstr "Filter" -#: src/language/constants.ts:19 src/views/site/SiteAdd.vue:97 +#: src/language/constants.ts:19 src/views/site/site_add/SiteAdd.vue:97 msgid "Finished" msgstr "Erledigt" @@ -1243,11 +1500,15 @@ msgstr "Hole das Zertifikat, bitte warten..." msgid "Github Proxy" msgstr "" +#: src/constants/errors/backup.ts:54 +msgid "Hash verification failed: file integrity compromised" +msgstr "" + #: src/components/SensitiveString/SensitiveString.vue:40 msgid "Hide" msgstr "Verstecken" -#: src/routes/index.ts:30 +#: src/routes/index.ts:47 msgid "Home" msgstr "Startseite" @@ -1302,7 +1563,8 @@ msgstr "" msgid "Import" msgstr "Import" -#: src/routes/index.ts:174 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:46 +#: src/views/certificate/CertificateEditor.vue:85 #, fuzzy msgid "Import Certificate" msgstr "Zertifikatsstatus" @@ -1328,7 +1590,7 @@ msgstr "Füge den Code aus der App ein:" msgid "Input the recovery code:" msgstr "Füge den Wiederherstellungscode ein:" -#: src/routes/index.ts:312 src/views/other/Install.vue:134 +#: src/routes/modules/auth.ts:8 src/views/other/Install.vue:134 msgid "Install" msgstr "Installieren" @@ -1346,6 +1608,19 @@ msgstr "Intervall" msgid "Invalid" msgstr "Ungültige E-Mail!" +#: src/constants/errors/backup.ts:42 +msgid "Invalid AES IV format: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:41 +msgid "Invalid AES key format: {0}" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:67 +#, fuzzy +msgid "Invalid file object" +msgstr "Ungültige E-Mail!" + #: src/views/config/components/Rename.vue:64 #: src/views/config/ConfigEditor.vue:250 #, fuzzy @@ -1361,6 +1636,10 @@ msgstr "Ungültiger Ordnername" msgid "Invalid otp code" msgstr "Ungültiger 2FA- oder Wiederherstellungscode" +#: src/constants/errors/backup.ts:25 +msgid "Invalid padding in decrypted data" +msgstr "" + #: src/components/TwoFA/use2FAModal.ts:61 msgid "Invalid passcode or recovery code" msgstr "Ungültiger Passcode oder Wiederherstellungscode" @@ -1374,6 +1653,11 @@ msgstr "Ungültiger 2FA- oder Wiederherstellungscode" msgid "Invalid request format" msgstr "" +#: src/constants/errors/backup.ts:40 +#, fuzzy +msgid "Invalid security token format" +msgstr "Ungültiger 2FA- oder Wiederherstellungscode" + #: src/views/preference/AuthSettings.vue:18 msgid "IP" msgstr "" @@ -1500,7 +1784,7 @@ msgstr "Orte" msgid "Log" msgstr "Login" -#: src/routes/index.ts:318 src/views/other/Login.vue:222 +#: src/routes/modules/auth.ts:14 src/views/other/Login.vue:222 msgid "Login" msgstr "Login" @@ -1542,21 +1826,21 @@ msgstr "" "zum HTTPChallengePort (Standard: 9180) konfiguriert hast, bevor du das " "Zertifikat erhältst." -#: src/routes/index.ts:108 src/views/config/ConfigEditor.vue:102 +#: src/routes/modules/config.ts:10 src/views/config/ConfigEditor.vue:102 #: src/views/config/ConfigEditor.vue:139 src/views/config/ConfigList.vue:69 msgid "Manage Configs" msgstr "Verwalte Konfigurationen" -#: src/routes/index.ts:47 src/views/site/site_list/SiteList.vue:94 +#: src/routes/modules/sites.ts:10 src/views/site/site_list/SiteList.vue:94 msgid "Manage Sites" msgstr "Verwalte Seiten" -#: src/routes/index.ts:89 src/views/stream/StreamList.vue:119 +#: src/routes/modules/streams.ts:10 src/views/stream/StreamList.vue:119 #, fuzzy msgid "Manage Streams" msgstr "Verwalte Seiten" -#: src/routes/index.ts:257 src/views/user/User.vue:10 +#: src/routes/modules/user.ts:10 src/views/user/User.vue:10 msgid "Manage Users" msgstr "Verwalte Benutzer" @@ -1595,12 +1879,13 @@ msgstr "Erweiterter Modus" msgid "Modify" msgstr "Konfiguration bearbeiten" -#: src/routes/index.ts:164 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:36 +#: src/views/certificate/CertificateEditor.vue:85 #, fuzzy msgid "Modify Certificate" msgstr "Zertifikatsstatus" -#: src/views/site/SiteAdd.vue:154 +#: src/views/site/site_add/SiteAdd.vue:154 msgid "Modify Config" msgstr "Konfiguration bearbeiten" @@ -1665,7 +1950,7 @@ msgstr "Neue Version veröffentlicht" #: src/views/certificate/WildcardCertificate.vue:91 #: src/views/site/cert/components/ObtainCert.vue:211 -#: src/views/site/SiteAdd.vue:141 +#: src/views/site/site_add/SiteAdd.vue:141 msgid "Next" msgstr "Nächster" @@ -1701,6 +1986,16 @@ msgstr "" msgid "Nginx conf not include stream-enabled" msgstr "" +#: src/constants/errors/backup.ts:18 +#, fuzzy +msgid "Nginx config directory is not set" +msgstr "Nginx-Log-Verzeichnis-Whitelist" + +#: src/views/system/Backup/SystemRestore.vue:84 +#, fuzzy +msgid "Nginx configuration has been restored" +msgstr "Name der Konfiguration" + #: src/views/site/site_edit/SiteEdit.vue:223 #: src/views/stream/StreamEdit.vue:208 #, fuzzy @@ -1724,7 +2019,7 @@ msgstr "Nginx Fehlerlog-Pfad" msgid "Nginx is not running" msgstr "Nginx läuft nicht" -#: src/routes/index.ts:202 src/views/nginx_log/NginxLog.vue:148 +#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:148 msgid "Nginx Log" msgstr "Nginx-Log" @@ -1754,6 +2049,18 @@ msgstr "Beffehl zum Neustarten von Nginx" msgid "Nginx restarted successfully" msgstr "Speichern erfolgreich" +#: src/views/system/Backup/SystemRestore.vue:88 +#, fuzzy +msgid "Nginx UI configuration has been restored" +msgstr "Name der Konfiguration" + +#: src/views/system/Backup/SystemRestore.vue:93 +#, fuzzy +msgid "" +"Nginx UI configuration has been restored and will restart automatically in a " +"few seconds." +msgstr "Name der Konfiguration" + #: src/components/ChatGPT/ChatGPT.vue:374 #: src/components/Notification/Notification.vue:133 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:63 @@ -1784,7 +2091,7 @@ msgstr "Node-Secret" msgid "Not After" msgstr "Nicht nach" -#: src/routes/index.ts:324 +#: src/routes/modules/error.ts:8 msgid "Not Found" msgstr "Nicth gefunden" @@ -1811,7 +2118,8 @@ msgstr "" msgid "Notification" msgstr "Zertifikat ist gültig" -#: src/components/Notification/Notification.vue:131 src/routes/index.ts:248 +#: src/components/Notification/Notification.vue:131 +#: src/routes/modules/notifications.ts:10 #, fuzzy msgid "Notifications" msgstr "Zertifikat ist gültig" @@ -1863,6 +2171,8 @@ msgstr "OK" #: src/views/site/site_list/SiteList.vue:144 #: src/views/stream/components/RightSettings.vue:50 #: src/views/stream/StreamList.vue:164 +#: src/views/system/Backup/BackupCreator.vue:149 +#: src/views/system/Backup/SystemRestore.vue:94 msgid "OK" msgstr "OK" @@ -1878,6 +2188,10 @@ msgstr "" msgid "Online" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:24 +msgid "Only zip files are allowed" +msgstr "" + #: src/views/preference/Preference.vue:170 msgid "OpenAI" msgstr "" @@ -1993,6 +2307,15 @@ msgstr "" msgid "Please enter the OTP code:" msgstr "Bitte gib den OTP-Code ein:" +#: src/views/system/Backup/SystemRestore.vue:58 +#, fuzzy +msgid "Please enter the security token" +msgstr "Bitte gib den OTP-Code ein:" + +#: src/views/system/Backup/SystemRestore.vue:153 +msgid "Please enter the security token received during backup" +msgstr "" + #: src/views/certificate/DNSCredential.vue:53 msgid "" "Please fill in the API authentication credentials provided by your DNS " @@ -2067,6 +2390,15 @@ msgstr "" "Bitte beachte, dass die Zeiteinheiten der unten aufgeführten Konfigurationen " "alle in Sekunden angegeben sind." +#: src/views/system/Backup/BackupCreator.vue:107 +msgid "Please save this security token, you will need it for restoration:" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:53 +#, fuzzy +msgid "Please select a backup file" +msgstr "Bitte wähle mindestens einen Knoten aus!" + #: src/views/environment/Environment.vue:58 msgid "Please select at least one node to upgrade" msgstr "Bitte wähle mindestens einen Knoten zum Upgrade aus" @@ -2077,7 +2409,7 @@ msgstr "Bitte wähle mindestens einen Knoten zum Upgrade aus" msgid "Pre-release" msgstr "Vorabversion" -#: src/routes/index.ts:266 src/views/preference/Preference.vue:141 +#: src/routes/modules/preference.ts:10 src/views/preference/Preference.vue:141 msgid "Preference" msgstr "Einstellungen" @@ -2361,6 +2693,21 @@ msgstr "Neustart" msgid "Restarting" msgstr "Starte neu" +#: src/views/system/Backup/SystemRestore.vue:81 +#, fuzzy +msgid "Restore completed successfully" +msgstr "Erfolgreich deaktiviert" + +#: src/views/system/Backup/SystemRestore.vue:165 +#, fuzzy +msgid "Restore Nginx Configuration" +msgstr "Name der Konfiguration" + +#: src/views/system/Backup/SystemRestore.vue:176 +#, fuzzy +msgid "Restore Nginx UI Configuration" +msgstr "Name der Konfiguration" + #: src/views/preference/AuthSettings.vue:107 msgid "RP Display Name" msgstr "RP-Anzeigename" @@ -2404,7 +2751,7 @@ msgstr "Anweisung speichern" #: src/views/config/ConfigEditor.vue:171 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:41 -#: src/views/site/SiteAdd.vue:46 +#: src/views/site/site_add/SiteAdd.vue:46 msgid "Save error %{msg}" msgstr "Fehler beim Speichern %{msg}" @@ -2458,7 +2805,8 @@ msgstr "Speichern erfolgreich" #: src/views/config/ConfigEditor.vue:167 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:39 -#: src/views/site/site_edit/SiteEdit.vue:152 src/views/site/SiteAdd.vue:37 +#: src/views/site/site_add/SiteAdd.vue:37 +#: src/views/site/site_edit/SiteEdit.vue:152 #: src/views/stream/StreamEdit.vue:139 msgid "Saved successfully" msgstr "Speichern erfolgreich" @@ -2476,11 +2824,20 @@ msgstr "SDK" msgid "Secret has been copied" msgstr "Schlüssel wurde kopiert" +#: src/views/system/Backup/SystemRestore.vue:150 +msgid "Security Token" +msgstr "" + +#: src/views/system/Backup/BackupCreator.vue:94 +#, fuzzy +msgid "Security Token Information" +msgstr "Ungültiger 2FA- oder Wiederherstellungscode" + #: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:189 msgid "Selector" msgstr "Auswähler" -#: src/routes/index.ts:283 src/views/system/SelfCheck/SelfCheck.vue:42 +#: src/routes/modules/system.ts:19 src/views/system/SelfCheck/SelfCheck.vue:42 msgid "Self Check" msgstr "" @@ -2550,11 +2907,12 @@ msgstr "Mit einem Passkey anmelden" msgid "Single Directive" msgstr "Einzige Anweisung" -#: src/routes/index.ts:71 src/views/site/site_category/SiteCategory.vue:10 +#: src/routes/modules/sites.ts:34 +#: src/views/site/site_category/SiteCategory.vue:10 msgid "Site Categories" msgstr "Seitenkategorien" -#: src/views/site/SiteAdd.vue:147 +#: src/views/site/site_add/SiteAdd.vue:147 #, fuzzy msgid "Site Config Created Successfully" msgstr "Domain-Konfiguration erfolgreich erstellt" @@ -2564,7 +2922,7 @@ msgstr "Domain-Konfiguration erfolgreich erstellt" msgid "Site is enabled" msgstr "Deaktiviert" -#: src/routes/index.ts:224 +#: src/routes/modules/nginx_log.ts:31 #, fuzzy msgid "Site Logs" msgstr "Liste der Seiten" @@ -2579,7 +2937,7 @@ msgstr "File Not Found" msgid "Sites Directory" msgstr "Anweisung" -#: src/routes/index.ts:56 +#: src/routes/modules/sites.ts:19 msgid "Sites List" msgstr "Liste der Seiten" @@ -2623,6 +2981,10 @@ msgstr "Login" msgid "Stable" msgstr "Altiviert" +#: src/views/system/Backup/SystemRestore.vue:187 +msgid "Start Restore" +msgstr "" + #: src/views/certificate/ACMEUser.vue:65 #: src/views/certificate/CertificateList/certColumns.tsx:68 #: src/views/environment/envColumns.tsx:44 @@ -2674,6 +3036,10 @@ msgid "" "guide/nginx-proxy-example.html" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:140 +msgid "Supported file type: .zip" +msgstr "" + #: src/views/dashboard/ServerAnalytic.vue:236 #: src/views/dashboard/ServerAnalytic.vue:237 msgid "Swap" @@ -2737,7 +3103,7 @@ msgstr "Zertifikat ist gültig" msgid "Sync Config Success" msgstr "Zertifikat ist gültig" -#: src/views/site/site_category/SiteCategory.vue:17 +#: src/views/site/site_category/SiteCategory.vue:18 msgid "Sync Nodes" msgstr "Synchrone Knoten" @@ -2755,20 +3121,30 @@ msgstr "Synchronisieren mit" msgid "Synchronization" msgstr "Synchronisation" -#: src/routes/index.ts:275 +#: src/routes/modules/system.ts:11 msgid "System" msgstr "System" +#: src/views/system/Backup/BackupCreator.vue:71 +#, fuzzy +msgid "System Backup" +msgstr "System" + #: src/views/certificate/ACMEUserSelector.vue:88 msgid "System Initial User" msgstr "System-Startbenutzer" +#: src/views/system/Backup/SystemRestore.vue:117 +#, fuzzy +msgid "System Restore" +msgstr "System" + #: src/constants/errors/self_check.ts:2 #, fuzzy msgid "Task not found" msgstr "File Not Found" -#: src/routes/index.ts:194 src/views/terminal/Terminal.vue:114 +#: src/routes/modules/terminal.ts:10 src/views/terminal/Terminal.vue:114 msgid "Terminal" msgstr "Terminal" @@ -2828,7 +3204,7 @@ msgstr "" "Der Knotenname sollte nur Buchstaben, Unicode, Zahlen, Bindestriche, " "Doppelpunkte und Punkte enthalten." -#: src/views/site/SiteAdd.vue:120 +#: src/views/site/site_add/SiteAdd.vue:120 #, fuzzy msgid "The parameter of server_name is required" msgstr "server_name-Parameter ist erforderlich" @@ -2923,10 +3299,28 @@ msgid "" msgstr "" "Dieses Feld sollte nur Buchstaben, Unicode-Zeichen, Zahlen und -_ enthalten." +#: src/views/system/Backup/BackupCreator.vue:141 +msgid "" +"This token will only be shown once and cannot be retrieved later. Please " +"make sure to save it in a secure location." +msgstr "" + #: src/constants/form_errors.ts:4 msgid "This value is already taken" msgstr "Dieser Wert ist bereits vergeben" +#: src/views/system/Backup/SystemRestore.vue:169 +msgid "" +"This will restore all Nginx configuration files. Nginx will restart after " +"the restoration is complete." +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:180 +msgid "" +"This will restore configuration files and database. Nginx UI will restart " +"after the restoration is complete." +msgstr "" + #: src/views/environment/BatchUpgrader.vue:182 msgid "" "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}." @@ -3044,7 +3438,7 @@ msgstr "Aktualisiert am" msgid "Updated successfully" msgstr "Speichern erfolgreich" -#: src/routes/index.ts:297 src/views/environment/Environment.vue:66 +#: src/routes/modules/system.ts:40 src/views/environment/Environment.vue:66 #: src/views/system/Upgrade.vue:143 src/views/system/Upgrade.vue:226 msgid "Upgrade" msgstr "Upgrade" @@ -3111,6 +3505,10 @@ msgstr "Benutzername (*)" msgid "Valid" msgstr "Gültig" +#: src/views/system/Backup/SystemRestore.vue:159 +msgid "Verify Backup File Integrity" +msgstr "" + #: src/views/environment/envColumns.tsx:31 msgid "Version" msgstr "" @@ -3147,10 +3545,18 @@ msgstr "Anzeigen" #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33 #: src/views/notification/notificationColumns.tsx:22 #: src/views/preference/components/AddPasskey.vue:82 -#: src/views/site/SiteAdd.vue:115 +#: src/views/site/site_add/SiteAdd.vue:115 +#: src/views/system/Backup/BackupCreator.vue:138 msgid "Warning" msgstr "Warnung" +#: src/views/system/Backup/SystemRestore.vue:121 +msgid "" +"Warning: Restore operation will overwrite current configurations. Make sure " +"you have a valid backup file and security token, and carefully select what " +"to restore." +msgstr "" + #: src/views/certificate/DNSCredential.vue:56 msgid "" "We will add one or more TXT records to the DNS records of your domain for " @@ -3260,6 +3666,10 @@ msgstr "" msgid "Your passkeys" msgstr "Deine Passkeys" +#, fuzzy +#~ msgid "Restart Required" +#~ msgstr "Starte neu" + #~ msgid "Deploy %{conf_name} to %{node_name} successfully" #~ msgstr "Ausführen von %{conf_name} auf %{node_name} erfolgreich" @@ -3300,9 +3710,6 @@ msgstr "Deine Passkeys" #~ msgid "Enable successfully" #~ msgstr "Erfolgreich aktiviert" -#~ msgid "Please select at least one node!" -#~ msgstr "Bitte wähle mindestens einen Knoten aus!" - #, fuzzy #~ msgid "Please upgrade the remote Nginx UI to the latest version" #~ msgstr "Speichern erfolgreich" diff --git a/app/src/language/en/app.po b/app/src/language/en/app.po index a642a55d..81c28070 100644 --- a/app/src/language/en/app.po +++ b/app/src/language/en/app.po @@ -17,16 +17,16 @@ msgstr "" msgid "2FA Settings" msgstr "" -#: src/routes/index.ts:290 +#: src/routes/modules/system.ts:26 msgid "About" msgstr "About" -#: src/routes/index.ts:210 src/views/site/ngx_conf/LogEntry.vue:75 +#: src/routes/modules/nginx_log.ts:17 src/views/site/ngx_conf/LogEntry.vue:75 #, fuzzy msgid "Access Logs" msgstr "Sites List" -#: src/routes/index.ts:148 src/views/certificate/ACMEUser.vue:113 +#: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:113 #: src/views/certificate/ACMEUserSelector.vue:85 #, fuzzy msgid "ACME User" @@ -39,7 +39,7 @@ msgstr "Username" #: src/views/environment/envColumns.tsx:97 #: src/views/notification/notificationColumns.tsx:65 #: src/views/preference/AuthSettings.vue:30 -#: src/views/site/site_category/columns.ts:29 +#: src/views/site/site_category/columns.ts:28 #: src/views/site/site_list/columns.tsx:76 src/views/stream/StreamList.vue:49 #: src/views/user/userColumns.tsx:60 msgid "Action" @@ -60,7 +60,7 @@ msgstr "" msgid "Add a passkey" msgstr "" -#: src/routes/index.ts:118 src/views/config/ConfigEditor.vue:144 +#: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:144 #: src/views/config/ConfigEditor.vue:204 #, fuzzy msgid "Add Configuration" @@ -75,7 +75,7 @@ msgstr "Add Directive Below" msgid "Add Location" msgstr "Add Location" -#: src/routes/index.ts:63 src/views/site/SiteAdd.vue:89 +#: src/routes/modules/sites.ts:26 src/views/site/site_add/SiteAdd.vue:89 msgid "Add Site" msgstr "Add Site" @@ -263,6 +263,10 @@ msgstr "Auto-renewal disabled for %{name}" msgid "Auto-renewal enabled for %{name}" msgstr "Auto-renewal enabled for %{name}" +#: src/views/system/Backup/SystemRestore.vue:92 +msgid "Automatic Restart" +msgstr "" + #: src/views/certificate/CertificateEditor.vue:255 #: src/views/config/ConfigEditor.vue:213 src/views/config/ConfigList.vue:106 #: src/views/config/ConfigList.vue:180 src/views/nginx_log/NginxLog.vue:173 @@ -280,6 +284,25 @@ msgstr "Back" msgid "Back to list" msgstr "" +#: src/routes/modules/system.ts:33 +#, fuzzy +msgid "Backup" +msgstr "Back" + +#: src/views/system/Backup/SystemRestore.vue:100 +msgid "Backup file integrity check failed, it may have been tampered with" +msgstr "" + +#: src/constants/errors/backup.ts:39 +#, fuzzy +msgid "Backup file not found: {0}" +msgstr "File Not Found" + +#: src/views/system/Backup/BackupCreator.vue:42 +#, fuzzy +msgid "Backup has been downloaded successfully" +msgstr "Saved successfully" + #: src/views/preference/AuthSettings.vue:129 msgid "Ban Threshold Minutes" msgstr "" @@ -292,7 +315,7 @@ msgstr "" msgid "Banned Until" msgstr "" -#: src/views/site/SiteAdd.vue:95 +#: src/views/site/site_add/SiteAdd.vue:95 msgid "Base information" msgstr "Base information" @@ -407,13 +430,13 @@ msgid_plural "Certificates Status" msgstr[0] "Certificate Status" msgstr[1] "Certificate Status" -#: src/routes/index.ts:139 +#: src/routes/modules/certificates.ts:11 #: src/views/certificate/CertificateList/Certificate.vue:13 #, fuzzy msgid "Certificates" msgstr "Certificate Status" -#: src/routes/index.ts:156 +#: src/routes/modules/certificates.ts:28 #, fuzzy msgid "Certificates List" msgstr "Certificate is valid" @@ -488,6 +511,10 @@ msgstr "" msgid "Cleared successfully" msgstr "Disabled successfully" +#: src/views/system/Backup/SystemRestore.vue:137 +msgid "Click or drag backup file to this area to upload" +msgstr "" + #: src/views/preference/components/TOTP.vue:110 msgid "Click to copy" msgstr "" @@ -504,6 +531,11 @@ msgstr "Comments" msgid "Comments" msgstr "Comments" +#: src/constants/errors/backup.ts:13 +#, fuzzy +msgid "Config path is empty" +msgstr "Configurations" + #: src/views/site/ngx_conf/config_template/ConfigTemplate.vue:84 #, fuzzy msgid "Config Templates" @@ -513,7 +545,7 @@ msgstr "Configurations" msgid "Configuration file is test successful" msgstr "" -#: src/views/site/SiteAdd.vue:101 +#: src/views/site/site_add/SiteAdd.vue:101 msgid "Configuration Name" msgstr "Configuration Name" @@ -521,7 +553,7 @@ msgstr "Configuration Name" msgid "Configurations" msgstr "Configurations" -#: src/views/site/SiteAdd.vue:96 +#: src/views/site/site_add/SiteAdd.vue:96 msgid "Configure SSL" msgstr "Configure SSL" @@ -545,7 +577,12 @@ msgstr "Content" msgid "Copied" msgstr "" +#: src/views/system/Backup/BackupCreator.vue:128 +msgid "Copied!" +msgstr "" + #: src/components/SensitiveString/SensitiveString.vue:37 +#: src/views/system/Backup/BackupCreator.vue:128 msgid "Copy" msgstr "" @@ -570,10 +607,15 @@ msgstr "CPU:" msgid "Create" msgstr "Created at" -#: src/views/site/SiteAdd.vue:157 +#: src/views/site/site_add/SiteAdd.vue:157 msgid "Create Another" msgstr "Create Another" +#: src/views/system/Backup/BackupCreator.vue:86 +#, fuzzy +msgid "Create Backup" +msgstr "Created at" + #: src/views/config/ConfigList.vue:116 #, fuzzy msgid "Create File" @@ -584,9 +626,15 @@ msgstr "Created at" msgid "Create Folder" msgstr "Create Another" +#: src/views/system/Backup/BackupCreator.vue:75 +msgid "" +"Create system backups including Nginx configuration and Nginx UI settings. " +"Backup files will be automatically downloaded to your computer." +msgstr "" + #: src/views/notification/notificationColumns.tsx:58 #: src/views/preference/components/Passkey.vue:95 -#: src/views/site/site_category/columns.ts:15 src/views/user/userColumns.tsx:48 +#: src/views/site/site_category/columns.ts:16 src/views/user/userColumns.tsx:48 msgid "Created at" msgstr "Created at" @@ -630,7 +678,7 @@ msgid "" "indicator." msgstr "" -#: src/routes/index.ts:38 src/views/config/ConfigEditor.vue:134 +#: src/routes/modules/dashboard.ts:10 src/views/config/ConfigEditor.vue:134 #: src/views/config/ConfigEditor.vue:97 src/views/config/ConfigList.vue:64 msgid "Dashboard" msgstr "Dashboard" @@ -826,7 +874,8 @@ msgstr "Disabled successfully" msgid "Disk IO" msgstr "Disk IO" -#: src/routes/index.ts:184 src/views/certificate/DNSCredential.vue:40 +#: src/routes/modules/certificates.ts:56 +#: src/views/certificate/DNSCredential.vue:40 msgid "DNS Credentials" msgstr "" @@ -941,15 +990,15 @@ msgstr "Edit %{n}" msgid "Edit %{n}" msgstr "Edit %{n}" -#: src/routes/index.ts:128 src/views/config/ConfigEditor.vue:204 +#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:204 msgid "Edit Configuration" msgstr "Edit Configuration" -#: src/routes/index.ts:78 +#: src/routes/modules/sites.ts:41 msgid "Edit Site" msgstr "Edit Site" -#: src/routes/index.ts:98 +#: src/routes/modules/streams.ts:19 #, fuzzy msgid "Edit Stream" msgstr "Edit Site" @@ -978,7 +1027,7 @@ msgstr "Enabled successfully" msgid "Enable auto-renewal failed for %{name}" msgstr "Enable auto-renewal failed for %{name}" -#: src/views/site/SiteAdd.vue:43 +#: src/views/site/site_add/SiteAdd.vue:43 msgid "Enable failed" msgstr "Enable failed" @@ -1044,8 +1093,9 @@ msgstr "Enable TLS" msgid "Enabled" msgstr "Enabled" +#: src/views/site/site_add/SiteAdd.vue:40 #: src/views/site/site_edit/RightSettings.vue:33 -#: src/views/site/site_list/SiteList.vue:46 src/views/site/SiteAdd.vue:40 +#: src/views/site/site_list/SiteList.vue:46 #: src/views/stream/components/RightSettings.vue:29 #: src/views/stream/StreamList.vue:61 msgid "Enabled successfully" @@ -1059,7 +1109,8 @@ msgstr "Encrypt website with Let's Encrypt" msgid "Environment variables cleaned" msgstr "" -#: src/routes/index.ts:234 src/views/dashboard/Environments.vue:83 +#: src/routes/modules/environments.ts:11 +#: src/views/dashboard/Environments.vue:83 #: src/views/environment/Environment.vue:43 #, fuzzy msgid "Environments" @@ -1070,7 +1121,7 @@ msgstr "Comments" msgid "Error" msgstr "" -#: src/routes/index.ts:217 src/views/site/ngx_conf/LogEntry.vue:83 +#: src/routes/modules/nginx_log.ts:24 src/views/site/ngx_conf/LogEntry.vue:83 msgid "Error Logs" msgstr "" @@ -1097,11 +1148,131 @@ msgstr "" msgid "Fail to obtain certificate" msgstr "Certificate is valid" +#: src/constants/errors/backup.ts:5 +#, fuzzy +msgid "Failed to backup Nginx config files: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:4 +msgid "Failed to backup Nginx UI files: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:17 +#, fuzzy +msgid "Failed to calculate hash: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:53 +msgid "Failed to calculate Nginx hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:52 +msgid "Failed to calculate Nginx UI hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:14 +msgid "Failed to copy config file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:15 +msgid "Failed to copy database directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:16 +#, fuzzy +msgid "Failed to copy database file: {0}" +msgstr "Failed to disable %{msg}" + +#: src/constants/errors/backup.ts:30 +msgid "Failed to copy file content: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:19 +msgid "Failed to copy Nginx config directory: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:9 #, fuzzy msgid "Failed to create backup" msgstr "Failed to enable %{msg}" +#: src/constants/errors/backup.ts:12 +#, fuzzy +msgid "Failed to create backup file: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:44 +#, fuzzy +msgid "Failed to create directory: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:46 +#, fuzzy +msgid "Failed to create file: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:6 +#, fuzzy +msgid "Failed to create hash info file: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:45 +#, fuzzy +msgid "Failed to create parent directory: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:32 +msgid "Failed to create restore directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:2 +#, fuzzy +msgid "Failed to create temporary directory" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:3 +#, fuzzy +msgid "Failed to create temporary subdirectory" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:9 +#, fuzzy +msgid "Failed to create zip archive: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:27 +#, fuzzy +msgid "Failed to create zip entry: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:26 +#, fuzzy +msgid "Failed to create zip file: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:29 +#, fuzzy +msgid "Failed to create zip header: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:24 +#, fuzzy +msgid "Failed to decrypt data: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:49 +#, fuzzy +msgid "Failed to decrypt file: {0}" +msgstr "Failed to disable %{msg}" + +#: src/constants/errors/backup.ts:35 +msgid "Failed to decrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:34 +msgid "Failed to decrypt Nginx UI directory: {0}" +msgstr "" + #: src/views/site/site_edit/RightSettings.vue:45 #: src/views/site/site_list/SiteList.vue:60 #: src/views/stream/components/RightSettings.vue:41 @@ -1116,25 +1287,114 @@ msgstr "Failed to disable %{msg}" msgid "Failed to enable %{msg}" msgstr "Failed to enable %{msg}" +#: src/constants/errors/backup.ts:23 +#, fuzzy +msgid "Failed to encrypt data: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:21 +#, fuzzy +msgid "Failed to encrypt file: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:8 +msgid "Failed to encrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:7 +msgid "Failed to encrypt Nginx UI directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:33 +#, fuzzy +msgid "Failed to extract archive: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:10 +#, fuzzy +msgid "Failed to generate AES key: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:11 +#, fuzzy +msgid "Failed to generate initialization vector: {0}" +msgstr "Certificate is valid" + #: src/language/constants.ts:5 #, fuzzy msgid "Failed to get certificate information" msgstr "Certificate is valid" +#: src/constants/errors/backup.ts:28 +#, fuzzy +msgid "Failed to open source file: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:47 +#, fuzzy +msgid "Failed to open zip entry: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:43 +#, fuzzy +msgid "Failed to open zip file: {0}" +msgstr "Failed to enable %{msg}" + #: src/constants/errors/self_check.ts:4 msgid "Failed to parse nginx.conf" msgstr "" +#: src/constants/errors/backup.ts:48 +#, fuzzy +msgid "Failed to read encrypted file: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:20 +#, fuzzy +msgid "Failed to read file: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:51 +#, fuzzy +msgid "Failed to read hash info file: {0}" +msgstr "Failed to enable %{msg}" + #: src/constants/errors/self_check.ts:3 #, fuzzy msgid "Failed to read nginx.conf" msgstr "Failed to enable %{msg}" +#: src/constants/errors/backup.ts:37 +#, fuzzy +msgid "Failed to restore Nginx configs: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:38 +msgid "Failed to restore Nginx UI files: {0}" +msgstr "" + #: src/views/site/site_edit/SiteEdit.vue:135 #: src/views/stream/StreamEdit.vue:122 msgid "Failed to save, syntax error(s) was detected in the configuration." msgstr "" +#: src/constants/errors/backup.ts:36 +#, fuzzy +msgid "Failed to verify hashes: {0}" +msgstr "Failed to enable %{msg}" + +#: src/constants/errors/backup.ts:50 +msgid "Failed to write decrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:22 +msgid "Failed to write encrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:31 +msgid "Failed to write to zip buffer: {0}" +msgstr "" + #: src/language/constants.ts:32 msgid "File exists" msgstr "" @@ -1151,7 +1411,7 @@ msgstr "" msgid "Filter" msgstr "" -#: src/language/constants.ts:19 src/views/site/SiteAdd.vue:97 +#: src/language/constants.ts:19 src/views/site/site_add/SiteAdd.vue:97 msgid "Finished" msgstr "Finished" @@ -1229,11 +1489,15 @@ msgstr "Getting the certificate, please wait..." msgid "Github Proxy" msgstr "" +#: src/constants/errors/backup.ts:54 +msgid "Hash verification failed: file integrity compromised" +msgstr "" + #: src/components/SensitiveString/SensitiveString.vue:40 msgid "Hide" msgstr "" -#: src/routes/index.ts:30 +#: src/routes/index.ts:47 msgid "Home" msgstr "Home" @@ -1281,7 +1545,8 @@ msgstr "" msgid "Import" msgstr "" -#: src/routes/index.ts:174 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:46 +#: src/views/certificate/CertificateEditor.vue:85 #, fuzzy msgid "Import Certificate" msgstr "Certificate Status" @@ -1307,7 +1572,7 @@ msgstr "" msgid "Input the recovery code:" msgstr "" -#: src/routes/index.ts:312 src/views/other/Install.vue:134 +#: src/routes/modules/auth.ts:8 src/views/other/Install.vue:134 msgid "Install" msgstr "Install" @@ -1325,6 +1590,21 @@ msgstr "" msgid "Invalid" msgstr "Invalid E-mail!" +#: src/constants/errors/backup.ts:42 +#, fuzzy +msgid "Invalid AES IV format: {0}" +msgstr "Invalid E-mail!" + +#: src/constants/errors/backup.ts:41 +#, fuzzy +msgid "Invalid AES key format: {0}" +msgstr "Invalid E-mail!" + +#: src/views/system/Backup/SystemRestore.vue:67 +#, fuzzy +msgid "Invalid file object" +msgstr "Invalid E-mail!" + #: src/views/config/components/Rename.vue:64 #: src/views/config/ConfigEditor.vue:250 #, fuzzy @@ -1341,6 +1621,10 @@ msgstr "Invalid E-mail!" msgid "Invalid otp code" msgstr "Invalid E-mail!" +#: src/constants/errors/backup.ts:25 +msgid "Invalid padding in decrypted data" +msgstr "" + #: src/components/TwoFA/use2FAModal.ts:61 msgid "Invalid passcode or recovery code" msgstr "" @@ -1355,6 +1639,11 @@ msgstr "Invalid E-mail!" msgid "Invalid request format" msgstr "Invalid E-mail!" +#: src/constants/errors/backup.ts:40 +#, fuzzy +msgid "Invalid security token format" +msgstr "Invalid E-mail!" + #: src/views/preference/AuthSettings.vue:18 msgid "IP" msgstr "" @@ -1482,7 +1771,7 @@ msgstr "Locations" msgid "Log" msgstr "Login" -#: src/routes/index.ts:318 src/views/other/Login.vue:222 +#: src/routes/modules/auth.ts:14 src/views/other/Login.vue:222 msgid "Login" msgstr "Login" @@ -1517,21 +1806,21 @@ msgstr "" "Make sure you have configured a reverse proxy for .well-known directory to " "HTTPChallengePort (default: 9180) before getting the certificate." -#: src/routes/index.ts:108 src/views/config/ConfigEditor.vue:102 +#: src/routes/modules/config.ts:10 src/views/config/ConfigEditor.vue:102 #: src/views/config/ConfigEditor.vue:139 src/views/config/ConfigList.vue:69 msgid "Manage Configs" msgstr "Manage Configs" -#: src/routes/index.ts:47 src/views/site/site_list/SiteList.vue:94 +#: src/routes/modules/sites.ts:10 src/views/site/site_list/SiteList.vue:94 msgid "Manage Sites" msgstr "Manage Sites" -#: src/routes/index.ts:89 src/views/stream/StreamList.vue:119 +#: src/routes/modules/streams.ts:10 src/views/stream/StreamList.vue:119 #, fuzzy msgid "Manage Streams" msgstr "Manage Sites" -#: src/routes/index.ts:257 src/views/user/User.vue:10 +#: src/routes/modules/user.ts:10 src/views/user/User.vue:10 msgid "Manage Users" msgstr "Manage Users" @@ -1570,12 +1859,13 @@ msgstr "Advance Mode" msgid "Modify" msgstr "Modify Config" -#: src/routes/index.ts:164 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:36 +#: src/views/certificate/CertificateEditor.vue:85 #, fuzzy msgid "Modify Certificate" msgstr "Certificate Status" -#: src/views/site/SiteAdd.vue:154 +#: src/views/site/site_add/SiteAdd.vue:154 msgid "Modify Config" msgstr "Modify Config" @@ -1640,7 +1930,7 @@ msgstr "" #: src/views/certificate/WildcardCertificate.vue:91 #: src/views/site/cert/components/ObtainCert.vue:211 -#: src/views/site/SiteAdd.vue:141 +#: src/views/site/site_add/SiteAdd.vue:141 msgid "Next" msgstr "Next" @@ -1676,6 +1966,16 @@ msgstr "" msgid "Nginx conf not include stream-enabled" msgstr "" +#: src/constants/errors/backup.ts:18 +#, fuzzy +msgid "Nginx config directory is not set" +msgstr "Configuration Name" + +#: src/views/system/Backup/SystemRestore.vue:84 +#, fuzzy +msgid "Nginx configuration has been restored" +msgstr "Configuration Name" + #: src/views/site/site_edit/SiteEdit.vue:223 #: src/views/stream/StreamEdit.vue:208 #, fuzzy @@ -1699,7 +1999,7 @@ msgstr "" msgid "Nginx is not running" msgstr "" -#: src/routes/index.ts:202 src/views/nginx_log/NginxLog.vue:148 +#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:148 msgid "Nginx Log" msgstr "" @@ -1730,6 +2030,18 @@ msgstr "" msgid "Nginx restarted successfully" msgstr "Saved successfully" +#: src/views/system/Backup/SystemRestore.vue:88 +#, fuzzy +msgid "Nginx UI configuration has been restored" +msgstr "Configuration Name" + +#: src/views/system/Backup/SystemRestore.vue:93 +#, fuzzy +msgid "" +"Nginx UI configuration has been restored and will restart automatically in a " +"few seconds." +msgstr "Configuration Name" + #: src/components/ChatGPT/ChatGPT.vue:374 #: src/components/Notification/Notification.vue:133 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:63 @@ -1761,7 +2073,7 @@ msgstr "Username" msgid "Not After" msgstr "" -#: src/routes/index.ts:324 +#: src/routes/modules/error.ts:8 msgid "Not Found" msgstr "Not Found" @@ -1785,7 +2097,8 @@ msgstr "" msgid "Notification" msgstr "Certificate is valid" -#: src/components/Notification/Notification.vue:131 src/routes/index.ts:248 +#: src/components/Notification/Notification.vue:131 +#: src/routes/modules/notifications.ts:10 #, fuzzy msgid "Notifications" msgstr "Certificate is valid" @@ -1836,6 +2149,8 @@ msgstr "" #: src/views/site/site_list/SiteList.vue:144 #: src/views/stream/components/RightSettings.vue:50 #: src/views/stream/StreamList.vue:164 +#: src/views/system/Backup/BackupCreator.vue:149 +#: src/views/system/Backup/SystemRestore.vue:94 msgid "OK" msgstr "" @@ -1850,6 +2165,10 @@ msgstr "" msgid "Online" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:24 +msgid "Only zip files are allowed" +msgstr "" + #: src/views/preference/Preference.vue:170 msgid "OpenAI" msgstr "" @@ -1960,6 +2279,14 @@ msgstr "" msgid "Please enter the OTP code:" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:58 +msgid "Please enter the security token" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:153 +msgid "Please enter the security token received during backup" +msgstr "" + #: src/views/certificate/DNSCredential.vue:53 msgid "" "Please fill in the API authentication credentials provided by your DNS " @@ -2023,6 +2350,15 @@ msgid "" "Please note that the unit of time configurations below are all in seconds." msgstr "" +#: src/views/system/Backup/BackupCreator.vue:107 +msgid "Please save this security token, you will need it for restoration:" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:53 +#, fuzzy +msgid "Please select a backup file" +msgstr "Please input your username!" + #: src/views/environment/Environment.vue:58 msgid "Please select at least one node to upgrade" msgstr "" @@ -2033,7 +2369,7 @@ msgstr "" msgid "Pre-release" msgstr "" -#: src/routes/index.ts:266 src/views/preference/Preference.vue:141 +#: src/routes/modules/preference.ts:10 src/views/preference/Preference.vue:141 msgid "Preference" msgstr "" @@ -2317,6 +2653,21 @@ msgstr "" msgid "Restarting" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:81 +#, fuzzy +msgid "Restore completed successfully" +msgstr "Disabled successfully" + +#: src/views/system/Backup/SystemRestore.vue:165 +#, fuzzy +msgid "Restore Nginx Configuration" +msgstr "Configuration Name" + +#: src/views/system/Backup/SystemRestore.vue:176 +#, fuzzy +msgid "Restore Nginx UI Configuration" +msgstr "Configuration Name" + #: src/views/preference/AuthSettings.vue:107 msgid "RP Display Name" msgstr "" @@ -2360,7 +2711,7 @@ msgstr "Save Directive" #: src/views/config/ConfigEditor.vue:171 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:41 -#: src/views/site/SiteAdd.vue:46 +#: src/views/site/site_add/SiteAdd.vue:46 msgid "Save error %{msg}" msgstr "Save error %{msg}" @@ -2414,7 +2765,8 @@ msgstr "Saved successfully" #: src/views/config/ConfigEditor.vue:167 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:39 -#: src/views/site/site_edit/SiteEdit.vue:152 src/views/site/SiteAdd.vue:37 +#: src/views/site/site_add/SiteAdd.vue:37 +#: src/views/site/site_edit/SiteEdit.vue:152 #: src/views/stream/StreamEdit.vue:139 msgid "Saved successfully" msgstr "Saved successfully" @@ -2431,12 +2783,21 @@ msgstr "" msgid "Secret has been copied" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:150 +msgid "Security Token" +msgstr "" + +#: src/views/system/Backup/BackupCreator.vue:94 +#, fuzzy +msgid "Security Token Information" +msgstr "Invalid E-mail!" + #: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:189 #, fuzzy msgid "Selector" msgstr "Directive" -#: src/routes/index.ts:283 src/views/system/SelfCheck/SelfCheck.vue:42 +#: src/routes/modules/system.ts:19 src/views/system/SelfCheck/SelfCheck.vue:42 msgid "Self Check" msgstr "" @@ -2504,11 +2865,12 @@ msgstr "" msgid "Single Directive" msgstr "Single Directive" -#: src/routes/index.ts:71 src/views/site/site_category/SiteCategory.vue:10 +#: src/routes/modules/sites.ts:34 +#: src/views/site/site_category/SiteCategory.vue:10 msgid "Site Categories" msgstr "" -#: src/views/site/SiteAdd.vue:147 +#: src/views/site/site_add/SiteAdd.vue:147 #, fuzzy msgid "Site Config Created Successfully" msgstr "Domain Config Created Successfully" @@ -2518,7 +2880,7 @@ msgstr "Domain Config Created Successfully" msgid "Site is enabled" msgstr "Disabled" -#: src/routes/index.ts:224 +#: src/routes/modules/nginx_log.ts:31 #, fuzzy msgid "Site Logs" msgstr "Sites List" @@ -2533,7 +2895,7 @@ msgstr "File Not Found" msgid "Sites Directory" msgstr "Directive" -#: src/routes/index.ts:56 +#: src/routes/modules/sites.ts:19 msgid "Sites List" msgstr "Sites List" @@ -2579,6 +2941,10 @@ msgstr "Login" msgid "Stable" msgstr "Enabled" +#: src/views/system/Backup/SystemRestore.vue:187 +msgid "Start Restore" +msgstr "" + #: src/views/certificate/ACMEUser.vue:65 #: src/views/certificate/CertificateList/certColumns.tsx:68 #: src/views/environment/envColumns.tsx:44 @@ -2632,6 +2998,10 @@ msgid "" "guide/nginx-proxy-example.html" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:140 +msgid "Supported file type: .zip" +msgstr "" + #: src/views/dashboard/ServerAnalytic.vue:236 #: src/views/dashboard/ServerAnalytic.vue:237 msgid "Swap" @@ -2695,7 +3065,7 @@ msgstr "Certificate is valid" msgid "Sync Config Success" msgstr "Certificate is valid" -#: src/views/site/site_category/SiteCategory.vue:17 +#: src/views/site/site_category/SiteCategory.vue:18 msgid "Sync Nodes" msgstr "" @@ -2714,20 +3084,28 @@ msgstr "Certificate is valid" msgid "Synchronization" msgstr "" -#: src/routes/index.ts:275 +#: src/routes/modules/system.ts:11 msgid "System" msgstr "" +#: src/views/system/Backup/BackupCreator.vue:71 +msgid "System Backup" +msgstr "" + #: src/views/certificate/ACMEUserSelector.vue:88 msgid "System Initial User" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:117 +msgid "System Restore" +msgstr "" + #: src/constants/errors/self_check.ts:2 #, fuzzy msgid "Task not found" msgstr "File Not Found" -#: src/routes/index.ts:194 src/views/terminal/Terminal.vue:114 +#: src/routes/modules/terminal.ts:10 src/views/terminal/Terminal.vue:114 msgid "Terminal" msgstr "Terminal" @@ -2782,7 +3160,7 @@ msgid "" "dashes, colons, and dots." msgstr "" -#: src/views/site/SiteAdd.vue:120 +#: src/views/site/site_add/SiteAdd.vue:120 #, fuzzy msgid "The parameter of server_name is required" msgstr "server_name parameter is required" @@ -2873,10 +3251,28 @@ msgid "" "This field should only contain letters, unicode characters, numbers, and -_." msgstr "" +#: src/views/system/Backup/BackupCreator.vue:141 +msgid "" +"This token will only be shown once and cannot be retrieved later. Please " +"make sure to save it in a secure location." +msgstr "" + #: src/constants/form_errors.ts:4 msgid "This value is already taken" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:169 +msgid "" +"This will restore all Nginx configuration files. Nginx will restart after " +"the restoration is complete." +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:180 +msgid "" +"This will restore configuration files and database. Nginx UI will restart " +"after the restoration is complete." +msgstr "" + #: src/views/environment/BatchUpgrader.vue:182 #, fuzzy msgid "" @@ -2980,7 +3376,7 @@ msgstr "Updated at" msgid "Updated successfully" msgstr "Saved successfully" -#: src/routes/index.ts:297 src/views/environment/Environment.vue:66 +#: src/routes/modules/system.ts:40 src/views/environment/Environment.vue:66 #: src/views/system/Upgrade.vue:143 src/views/system/Upgrade.vue:226 msgid "Upgrade" msgstr "" @@ -3048,6 +3444,10 @@ msgstr "Username (*)" msgid "Valid" msgstr "Invalid E-mail!" +#: src/views/system/Backup/SystemRestore.vue:159 +msgid "Verify Backup File Integrity" +msgstr "" + #: src/views/environment/envColumns.tsx:31 msgid "Version" msgstr "" @@ -3085,10 +3485,18 @@ msgstr "Basic Mode" #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33 #: src/views/notification/notificationColumns.tsx:22 #: src/views/preference/components/AddPasskey.vue:82 -#: src/views/site/SiteAdd.vue:115 +#: src/views/site/site_add/SiteAdd.vue:115 +#: src/views/system/Backup/BackupCreator.vue:138 msgid "Warning" msgstr "Warning" +#: src/views/system/Backup/SystemRestore.vue:121 +msgid "" +"Warning: Restore operation will overwrite current configurations. Make sure " +"you have a valid backup file and security token, and carefully select what " +"to restore." +msgstr "" + #: src/views/certificate/DNSCredential.vue:56 msgid "" "We will add one or more TXT records to the DNS records of your domain for " diff --git a/app/src/language/es/app.po b/app/src/language/es/app.po index 9439a421..057d5065 100644 --- a/app/src/language/es/app.po +++ b/app/src/language/es/app.po @@ -24,15 +24,15 @@ msgstr "2FA" msgid "2FA Settings" msgstr "Configuración de 2FA" -#: src/routes/index.ts:290 +#: src/routes/modules/system.ts:26 msgid "About" msgstr "Acerca de" -#: src/routes/index.ts:210 src/views/site/ngx_conf/LogEntry.vue:75 +#: src/routes/modules/nginx_log.ts:17 src/views/site/ngx_conf/LogEntry.vue:75 msgid "Access Logs" msgstr "Logs de acceso" -#: src/routes/index.ts:148 src/views/certificate/ACMEUser.vue:113 +#: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:113 #: src/views/certificate/ACMEUserSelector.vue:85 msgid "ACME User" msgstr "Usuario ACME" @@ -44,7 +44,7 @@ msgstr "Usuario ACME" #: src/views/environment/envColumns.tsx:97 #: src/views/notification/notificationColumns.tsx:65 #: src/views/preference/AuthSettings.vue:30 -#: src/views/site/site_category/columns.ts:29 +#: src/views/site/site_category/columns.ts:28 #: src/views/site/site_list/columns.tsx:76 src/views/stream/StreamList.vue:49 #: src/views/user/userColumns.tsx:60 msgid "Action" @@ -65,7 +65,7 @@ msgstr "Agregar" msgid "Add a passkey" msgstr "Agregar una llave de acceso" -#: src/routes/index.ts:118 src/views/config/ConfigEditor.vue:144 +#: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:144 #: src/views/config/ConfigEditor.vue:204 msgid "Add Configuration" msgstr "Agregar configuración" @@ -79,7 +79,7 @@ msgstr "Añadir directiva a continuación" msgid "Add Location" msgstr "Agregar Ubicación" -#: src/routes/index.ts:63 src/views/site/SiteAdd.vue:89 +#: src/routes/modules/sites.ts:26 src/views/site/site_add/SiteAdd.vue:89 msgid "Add Site" msgstr "Agregar Sitio" @@ -257,6 +257,10 @@ msgstr "Renovación automática deshabilitada por %{name}" msgid "Auto-renewal enabled for %{name}" msgstr "Renovación automática habilitada por %{name}" +#: src/views/system/Backup/SystemRestore.vue:92 +msgid "Automatic Restart" +msgstr "" + #: src/views/certificate/CertificateEditor.vue:255 #: src/views/config/ConfigEditor.vue:213 src/views/config/ConfigList.vue:106 #: src/views/config/ConfigList.vue:180 src/views/nginx_log/NginxLog.vue:173 @@ -273,6 +277,25 @@ msgstr "Volver al Inicio" msgid "Back to list" msgstr "Volver a la lista" +#: src/routes/modules/system.ts:33 +#, fuzzy +msgid "Backup" +msgstr "Volver" + +#: src/views/system/Backup/SystemRestore.vue:100 +msgid "Backup file integrity check failed, it may have been tampered with" +msgstr "" + +#: src/constants/errors/backup.ts:39 +#, fuzzy +msgid "Backup file not found: {0}" +msgstr "Archivo no Encontrado" + +#: src/views/system/Backup/BackupCreator.vue:42 +#, fuzzy +msgid "Backup has been downloaded successfully" +msgstr "Nginx recargado con éxito" + #: src/views/preference/AuthSettings.vue:129 msgid "Ban Threshold Minutes" msgstr "Umbral de Prohibición en Minutos" @@ -285,7 +308,7 @@ msgstr "IPs prohibidas" msgid "Banned Until" msgstr "Bloqueado hasta" -#: src/views/site/SiteAdd.vue:95 +#: src/views/site/site_add/SiteAdd.vue:95 msgid "Base information" msgstr "Información general" @@ -400,12 +423,12 @@ msgid_plural "Certificates Status" msgstr[0] "Estado del Certificado" msgstr[1] "Estado de los Certificados" -#: src/routes/index.ts:139 +#: src/routes/modules/certificates.ts:11 #: src/views/certificate/CertificateList/Certificate.vue:13 msgid "Certificates" msgstr "Certificados" -#: src/routes/index.ts:156 +#: src/routes/modules/certificates.ts:28 msgid "Certificates List" msgstr "Lista de Certificados" @@ -475,6 +498,10 @@ msgstr "Borrar" msgid "Cleared successfully" msgstr "Limpiado exitoso" +#: src/views/system/Backup/SystemRestore.vue:137 +msgid "Click or drag backup file to this area to upload" +msgstr "" + #: src/views/preference/components/TOTP.vue:110 msgid "Click to copy" msgstr "" @@ -490,6 +517,11 @@ msgstr "Comando" msgid "Comments" msgstr "Comentarios" +#: src/constants/errors/backup.ts:13 +#, fuzzy +msgid "Config path is empty" +msgstr "Plantillas de configuración" + #: src/views/site/ngx_conf/config_template/ConfigTemplate.vue:84 msgid "Config Templates" msgstr "Plantillas de configuración" @@ -498,7 +530,7 @@ msgstr "Plantillas de configuración" msgid "Configuration file is test successful" msgstr "El archivo de configuración se probó exitosamente" -#: src/views/site/SiteAdd.vue:101 +#: src/views/site/site_add/SiteAdd.vue:101 msgid "Configuration Name" msgstr "Nombre de la configuración" @@ -506,7 +538,7 @@ msgstr "Nombre de la configuración" msgid "Configurations" msgstr "Configuraciones" -#: src/views/site/SiteAdd.vue:96 +#: src/views/site/site_add/SiteAdd.vue:96 msgid "Configure SSL" msgstr "Configurar SSL" @@ -530,7 +562,13 @@ msgstr "Contenido" msgid "Copied" msgstr "Copiado" +#: src/views/system/Backup/BackupCreator.vue:128 +#, fuzzy +msgid "Copied!" +msgstr "Copiado" + #: src/components/SensitiveString/SensitiveString.vue:37 +#: src/views/system/Backup/BackupCreator.vue:128 msgid "Copy" msgstr "Copiar" @@ -555,10 +593,15 @@ msgstr "CPU:" msgid "Create" msgstr "Crear" -#: src/views/site/SiteAdd.vue:157 +#: src/views/site/site_add/SiteAdd.vue:157 msgid "Create Another" msgstr "Crear otro" +#: src/views/system/Backup/BackupCreator.vue:86 +#, fuzzy +msgid "Create Backup" +msgstr "Creado el" + #: src/views/config/ConfigList.vue:116 msgid "Create File" msgstr "Crear Archivo" @@ -567,9 +610,15 @@ msgstr "Crear Archivo" msgid "Create Folder" msgstr "Crear carpeta" +#: src/views/system/Backup/BackupCreator.vue:75 +msgid "" +"Create system backups including Nginx configuration and Nginx UI settings. " +"Backup files will be automatically downloaded to your computer." +msgstr "" + #: src/views/notification/notificationColumns.tsx:58 #: src/views/preference/components/Passkey.vue:95 -#: src/views/site/site_category/columns.ts:15 src/views/user/userColumns.tsx:48 +#: src/views/site/site_category/columns.ts:16 src/views/user/userColumns.tsx:48 msgid "Created at" msgstr "Creado el" @@ -614,7 +663,7 @@ msgstr "" "Personalice el nombre del servidor local para mostrarlo en el indicador de " "entorno." -#: src/routes/index.ts:38 src/views/config/ConfigEditor.vue:134 +#: src/routes/modules/dashboard.ts:10 src/views/config/ConfigEditor.vue:134 #: src/views/config/ConfigEditor.vue:97 src/views/config/ConfigList.vue:64 msgid "Dashboard" msgstr "Panel" @@ -804,7 +853,8 @@ msgstr "Desactivado con éxito" msgid "Disk IO" msgstr "I/O del disco" -#: src/routes/index.ts:184 src/views/certificate/DNSCredential.vue:40 +#: src/routes/modules/certificates.ts:56 +#: src/views/certificate/DNSCredential.vue:40 msgid "DNS Credentials" msgstr "Credenciales de DNS" @@ -914,15 +964,15 @@ msgstr "Editar %{n}" msgid "Edit %{n}" msgstr "Editar %{n}" -#: src/routes/index.ts:128 src/views/config/ConfigEditor.vue:204 +#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:204 msgid "Edit Configuration" msgstr "Editar Configuración" -#: src/routes/index.ts:78 +#: src/routes/modules/sites.ts:41 msgid "Edit Site" msgstr "Editar Sitio" -#: src/routes/index.ts:98 +#: src/routes/modules/streams.ts:19 msgid "Edit Stream" msgstr "Editar Transmisión" @@ -947,7 +997,7 @@ msgstr "Habilitar 2FA exitoso" msgid "Enable auto-renewal failed for %{name}" msgstr "No se pudo activar la renovación automática por %{name}" -#: src/views/site/SiteAdd.vue:43 +#: src/views/site/site_add/SiteAdd.vue:43 msgid "Enable failed" msgstr "Falló la habilitación" @@ -1013,8 +1063,9 @@ msgstr "Habilitar TLS" msgid "Enabled" msgstr "Habilitado" +#: src/views/site/site_add/SiteAdd.vue:40 #: src/views/site/site_edit/RightSettings.vue:33 -#: src/views/site/site_list/SiteList.vue:46 src/views/site/SiteAdd.vue:40 +#: src/views/site/site_list/SiteList.vue:46 #: src/views/stream/components/RightSettings.vue:29 #: src/views/stream/StreamList.vue:61 msgid "Enabled successfully" @@ -1028,7 +1079,8 @@ msgstr "Encriptar sitio web con Let's Encrypt" msgid "Environment variables cleaned" msgstr "Variables de entorno limpiadas" -#: src/routes/index.ts:234 src/views/dashboard/Environments.vue:83 +#: src/routes/modules/environments.ts:11 +#: src/views/dashboard/Environments.vue:83 #: src/views/environment/Environment.vue:43 msgid "Environments" msgstr "Entornos" @@ -1038,7 +1090,7 @@ msgstr "Entornos" msgid "Error" msgstr "Error" -#: src/routes/index.ts:217 src/views/site/ngx_conf/LogEntry.vue:83 +#: src/routes/modules/nginx_log.ts:24 src/views/site/ngx_conf/LogEntry.vue:83 msgid "Error Logs" msgstr "Logs de error" @@ -1063,11 +1115,130 @@ msgstr "Exportar" msgid "Fail to obtain certificate" msgstr "Falla al obtener el certificado" +#: src/constants/errors/backup.ts:5 +msgid "Failed to backup Nginx config files: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:4 +msgid "Failed to backup Nginx UI files: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:17 +#, fuzzy +msgid "Failed to calculate hash: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:53 +msgid "Failed to calculate Nginx hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:52 +msgid "Failed to calculate Nginx UI hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:14 +msgid "Failed to copy config file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:15 +msgid "Failed to copy database directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:16 +#, fuzzy +msgid "Failed to copy database file: {0}" +msgstr "Error al deshabilitar %{msg}" + +#: src/constants/errors/backup.ts:30 +msgid "Failed to copy file content: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:19 +msgid "Failed to copy Nginx config directory: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:9 #, fuzzy msgid "Failed to create backup" msgstr "Error al habilitar %{msg}" +#: src/constants/errors/backup.ts:12 +#, fuzzy +msgid "Failed to create backup file: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:44 +#, fuzzy +msgid "Failed to create directory: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:46 +#, fuzzy +msgid "Failed to create file: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:6 +#, fuzzy +msgid "Failed to create hash info file: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:45 +#, fuzzy +msgid "Failed to create parent directory: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:32 +msgid "Failed to create restore directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:2 +#, fuzzy +msgid "Failed to create temporary directory" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:3 +#, fuzzy +msgid "Failed to create temporary subdirectory" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:9 +#, fuzzy +msgid "Failed to create zip archive: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:27 +#, fuzzy +msgid "Failed to create zip entry: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:26 +#, fuzzy +msgid "Failed to create zip file: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:29 +#, fuzzy +msgid "Failed to create zip header: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:24 +#, fuzzy +msgid "Failed to decrypt data: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:49 +#, fuzzy +msgid "Failed to decrypt file: {0}" +msgstr "Error al deshabilitar %{msg}" + +#: src/constants/errors/backup.ts:35 +msgid "Failed to decrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:34 +msgid "Failed to decrypt Nginx UI directory: {0}" +msgstr "" + #: src/views/site/site_edit/RightSettings.vue:45 #: src/views/site/site_list/SiteList.vue:60 #: src/views/stream/components/RightSettings.vue:41 @@ -1082,24 +1253,110 @@ msgstr "Error al deshabilitar %{msg}" msgid "Failed to enable %{msg}" msgstr "Error al habilitar %{msg}" +#: src/constants/errors/backup.ts:23 +#, fuzzy +msgid "Failed to encrypt data: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:21 +#, fuzzy +msgid "Failed to encrypt file: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:8 +msgid "Failed to encrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:7 +msgid "Failed to encrypt Nginx UI directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:33 +#, fuzzy +msgid "Failed to extract archive: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:10 +#, fuzzy +msgid "Failed to generate AES key: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:11 +#, fuzzy +msgid "Failed to generate initialization vector: {0}" +msgstr "No se pudo obtener la información del certificado" + #: src/language/constants.ts:5 msgid "Failed to get certificate information" msgstr "No se pudo obtener la información del certificado" +#: src/constants/errors/backup.ts:28 +#, fuzzy +msgid "Failed to open source file: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:47 +#, fuzzy +msgid "Failed to open zip entry: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:43 +#, fuzzy +msgid "Failed to open zip file: {0}" +msgstr "Error al habilitar %{msg}" + #: src/constants/errors/self_check.ts:4 msgid "Failed to parse nginx.conf" msgstr "" +#: src/constants/errors/backup.ts:48 +msgid "Failed to read encrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:20 +#, fuzzy +msgid "Failed to read file: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:51 +msgid "Failed to read hash info file: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:3 msgid "Failed to read nginx.conf" msgstr "" +#: src/constants/errors/backup.ts:37 +msgid "Failed to restore Nginx configs: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:38 +msgid "Failed to restore Nginx UI files: {0}" +msgstr "" + #: src/views/site/site_edit/SiteEdit.vue:135 #: src/views/stream/StreamEdit.vue:122 msgid "Failed to save, syntax error(s) was detected in the configuration." msgstr "" "No se pudo guardar, se detectó un error(es) de sintaxis en la configuración." +#: src/constants/errors/backup.ts:36 +#, fuzzy +msgid "Failed to verify hashes: {0}" +msgstr "Error al habilitar %{msg}" + +#: src/constants/errors/backup.ts:50 +msgid "Failed to write decrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:22 +msgid "Failed to write encrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:31 +msgid "Failed to write to zip buffer: {0}" +msgstr "" + #: src/language/constants.ts:32 msgid "File exists" msgstr "El archivo existe" @@ -1116,7 +1373,7 @@ msgstr "" msgid "Filter" msgstr "Filtro" -#: src/language/constants.ts:19 src/views/site/SiteAdd.vue:97 +#: src/language/constants.ts:19 src/views/site/site_add/SiteAdd.vue:97 msgid "Finished" msgstr "Terminado" @@ -1193,11 +1450,15 @@ msgstr "Obteniendo el certificado, por favor espere..." msgid "Github Proxy" msgstr "Proxy Github" +#: src/constants/errors/backup.ts:54 +msgid "Hash verification failed: file integrity compromised" +msgstr "" + #: src/components/SensitiveString/SensitiveString.vue:40 msgid "Hide" msgstr "Ocultar" -#: src/routes/index.ts:30 +#: src/routes/index.ts:47 msgid "Home" msgstr "Inicio" @@ -1251,7 +1512,8 @@ msgstr "" msgid "Import" msgstr "Importar" -#: src/routes/index.ts:174 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:46 +#: src/views/certificate/CertificateEditor.vue:85 msgid "Import Certificate" msgstr "Importar Certificado" @@ -1276,7 +1538,7 @@ msgstr "Ingrese el código de la aplicación:" msgid "Input the recovery code:" msgstr "Ingrese el código de recuperación:" -#: src/routes/index.ts:312 src/views/other/Install.vue:134 +#: src/routes/modules/auth.ts:8 src/views/other/Install.vue:134 msgid "Install" msgstr "Instalar" @@ -1292,6 +1554,19 @@ msgstr "Intervalo" msgid "Invalid" msgstr "Inválido" +#: src/constants/errors/backup.ts:42 +msgid "Invalid AES IV format: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:41 +msgid "Invalid AES key format: {0}" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:67 +#, fuzzy +msgid "Invalid file object" +msgstr "Nombre de archivo inválido" + #: src/views/config/components/Rename.vue:64 #: src/views/config/ConfigEditor.vue:250 msgid "Invalid filename" @@ -1306,6 +1581,10 @@ msgstr "Nombre de carpeta inválido" msgid "Invalid otp code" msgstr "Código 2FA o de recuperación inválido" +#: src/constants/errors/backup.ts:25 +msgid "Invalid padding in decrypted data" +msgstr "" + #: src/components/TwoFA/use2FAModal.ts:61 msgid "Invalid passcode or recovery code" msgstr "Código de acceso o código de recuperación inválido" @@ -1319,6 +1598,11 @@ msgstr "Código 2FA o de recuperación inválido" msgid "Invalid request format" msgstr "" +#: src/constants/errors/backup.ts:40 +#, fuzzy +msgid "Invalid security token format" +msgstr "Código 2FA o de recuperación inválido" + #: src/views/preference/AuthSettings.vue:18 msgid "IP" msgstr "IP" @@ -1435,7 +1719,7 @@ msgstr "Ubicaciones" msgid "Log" msgstr "Registro" -#: src/routes/index.ts:318 src/views/other/Login.vue:222 +#: src/routes/modules/auth.ts:14 src/views/other/Login.vue:222 msgid "Login" msgstr "Acceso" @@ -1476,20 +1760,20 @@ msgstr "" "Asegúrese de haber configurado un proxy reverso para el directorio .well-" "known en HTTPChallengePort antes de obtener el certificado." -#: src/routes/index.ts:108 src/views/config/ConfigEditor.vue:102 +#: src/routes/modules/config.ts:10 src/views/config/ConfigEditor.vue:102 #: src/views/config/ConfigEditor.vue:139 src/views/config/ConfigList.vue:69 msgid "Manage Configs" msgstr "Administrar configuraciones" -#: src/routes/index.ts:47 src/views/site/site_list/SiteList.vue:94 +#: src/routes/modules/sites.ts:10 src/views/site/site_list/SiteList.vue:94 msgid "Manage Sites" msgstr "Administrar sitios" -#: src/routes/index.ts:89 src/views/stream/StreamList.vue:119 +#: src/routes/modules/streams.ts:10 src/views/stream/StreamList.vue:119 msgid "Manage Streams" msgstr "Administrar Transmisiones" -#: src/routes/index.ts:257 src/views/user/User.vue:10 +#: src/routes/modules/user.ts:10 src/views/user/User.vue:10 msgid "Manage Users" msgstr "Administrar usuarios" @@ -1525,11 +1809,12 @@ msgstr "Modelo" msgid "Modify" msgstr "Modificar" -#: src/routes/index.ts:164 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:36 +#: src/views/certificate/CertificateEditor.vue:85 msgid "Modify Certificate" msgstr "Modificar Certificado" -#: src/views/site/SiteAdd.vue:154 +#: src/views/site/site_add/SiteAdd.vue:154 msgid "Modify Config" msgstr "Modificar configuración" @@ -1590,7 +1875,7 @@ msgstr "Se liberó una nueva versión" #: src/views/certificate/WildcardCertificate.vue:91 #: src/views/site/cert/components/ObtainCert.vue:211 -#: src/views/site/SiteAdd.vue:141 +#: src/views/site/site_add/SiteAdd.vue:141 msgid "Next" msgstr "Siguiente" @@ -1626,6 +1911,16 @@ msgstr "" msgid "Nginx conf not include stream-enabled" msgstr "" +#: src/constants/errors/backup.ts:18 +#, fuzzy +msgid "Nginx config directory is not set" +msgstr "Lista blanca de directorios de registro de Nginx" + +#: src/views/system/Backup/SystemRestore.vue:84 +#, fuzzy +msgid "Nginx configuration has been restored" +msgstr "Error de análisis de configuración de Nginx" + #: src/views/site/site_edit/SiteEdit.vue:223 #: src/views/stream/StreamEdit.vue:208 msgid "Nginx Configuration Parse Error" @@ -1648,7 +1943,7 @@ msgstr "Ruta de registro de errores de Nginx" msgid "Nginx is not running" msgstr "Nginx no se está ejecutando" -#: src/routes/index.ts:202 src/views/nginx_log/NginxLog.vue:148 +#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:148 msgid "Nginx Log" msgstr "Registro Nginx" @@ -1678,6 +1973,18 @@ msgstr "Comando de inicio de terminal" msgid "Nginx restarted successfully" msgstr "Nginx reiniciado con éxito" +#: src/views/system/Backup/SystemRestore.vue:88 +#, fuzzy +msgid "Nginx UI configuration has been restored" +msgstr "Error de análisis de configuración de Nginx" + +#: src/views/system/Backup/SystemRestore.vue:93 +#, fuzzy +msgid "" +"Nginx UI configuration has been restored and will restart automatically in a " +"few seconds." +msgstr "Error de análisis de configuración de Nginx" + #: src/components/ChatGPT/ChatGPT.vue:374 #: src/components/Notification/Notification.vue:133 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:63 @@ -1708,7 +2015,7 @@ msgstr "Secreto del nodo" msgid "Not After" msgstr "No después de" -#: src/routes/index.ts:324 +#: src/routes/modules/error.ts:8 msgid "Not Found" msgstr "No encontrado" @@ -1734,7 +2041,8 @@ msgstr "" msgid "Notification" msgstr "Notificación" -#: src/components/Notification/Notification.vue:131 src/routes/index.ts:248 +#: src/components/Notification/Notification.vue:131 +#: src/routes/modules/notifications.ts:10 msgid "Notifications" msgstr "Notificaciones" @@ -1784,6 +2092,8 @@ msgstr "Ok" #: src/views/site/site_list/SiteList.vue:144 #: src/views/stream/components/RightSettings.vue:50 #: src/views/stream/StreamList.vue:164 +#: src/views/system/Backup/BackupCreator.vue:149 +#: src/views/system/Backup/SystemRestore.vue:94 msgid "OK" msgstr "OK" @@ -1798,6 +2108,10 @@ msgstr "Una vez que se complete la verificación, los registros se eliminarán." msgid "Online" msgstr "En línea" +#: src/views/system/Backup/SystemRestore.vue:24 +msgid "Only zip files are allowed" +msgstr "" + #: src/views/preference/Preference.vue:170 msgid "OpenAI" msgstr "OpenAI" @@ -1914,6 +2228,15 @@ msgstr "" msgid "Please enter the OTP code:" msgstr "Por favor, ingrese el código 2FA:" +#: src/views/system/Backup/SystemRestore.vue:58 +#, fuzzy +msgid "Please enter the security token" +msgstr "Por favor, ingrese el código 2FA:" + +#: src/views/system/Backup/SystemRestore.vue:153 +msgid "Please enter the security token received during backup" +msgstr "" + #: src/views/certificate/DNSCredential.vue:53 msgid "" "Please fill in the API authentication credentials provided by your DNS " @@ -1986,6 +2309,15 @@ msgstr "" "Tenga en cuenta que las siguientes configuraciones de unidades de tiempo " "están todas en segundos." +#: src/views/system/Backup/BackupCreator.vue:107 +msgid "Please save this security token, you will need it for restoration:" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:53 +#, fuzzy +msgid "Please select a backup file" +msgstr "¡Seleccione al menos un nodo!" + #: src/views/environment/Environment.vue:58 msgid "Please select at least one node to upgrade" msgstr "Seleccione al menos un nodo para actualizar" @@ -1996,7 +2328,7 @@ msgstr "Seleccione al menos un nodo para actualizar" msgid "Pre-release" msgstr "Prelanzamiento" -#: src/routes/index.ts:266 src/views/preference/Preference.vue:141 +#: src/routes/modules/preference.ts:10 src/views/preference/Preference.vue:141 msgid "Preference" msgstr "Configuración" @@ -2266,6 +2598,21 @@ msgstr "Reiniciar" msgid "Restarting" msgstr "Reiniciando" +#: src/views/system/Backup/SystemRestore.vue:81 +#, fuzzy +msgid "Restore completed successfully" +msgstr "Borrado exitoso" + +#: src/views/system/Backup/SystemRestore.vue:165 +#, fuzzy +msgid "Restore Nginx Configuration" +msgstr "Error de análisis de configuración de Nginx" + +#: src/views/system/Backup/SystemRestore.vue:176 +#, fuzzy +msgid "Restore Nginx UI Configuration" +msgstr "Error de análisis de configuración de Nginx" + #: src/views/preference/AuthSettings.vue:107 msgid "RP Display Name" msgstr "Nombre RP" @@ -2308,7 +2655,7 @@ msgstr "Guardar Directiva" #: src/views/config/ConfigEditor.vue:171 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:41 -#: src/views/site/SiteAdd.vue:46 +#: src/views/site/site_add/SiteAdd.vue:46 msgid "Save error %{msg}" msgstr "Error al guardar %{msg}" @@ -2361,7 +2708,8 @@ msgstr "Guardado con éxito" #: src/views/config/ConfigEditor.vue:167 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:39 -#: src/views/site/site_edit/SiteEdit.vue:152 src/views/site/SiteAdd.vue:37 +#: src/views/site/site_add/SiteAdd.vue:37 +#: src/views/site/site_edit/SiteEdit.vue:152 #: src/views/stream/StreamEdit.vue:139 msgid "Saved successfully" msgstr "Guardado con éxito" @@ -2380,11 +2728,20 @@ msgstr "SDK" msgid "Secret has been copied" msgstr "El secreto ha sido copiado" +#: src/views/system/Backup/SystemRestore.vue:150 +msgid "Security Token" +msgstr "" + +#: src/views/system/Backup/BackupCreator.vue:94 +#, fuzzy +msgid "Security Token Information" +msgstr "Código 2FA o de recuperación inválido" + #: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:189 msgid "Selector" msgstr "Seleccionador" -#: src/routes/index.ts:283 src/views/system/SelfCheck/SelfCheck.vue:42 +#: src/routes/modules/system.ts:19 src/views/system/SelfCheck/SelfCheck.vue:42 msgid "Self Check" msgstr "" @@ -2454,11 +2811,12 @@ msgstr "Iniciar sesión con una llave de acceso" msgid "Single Directive" msgstr "Directiva de una sola línea" -#: src/routes/index.ts:71 src/views/site/site_category/SiteCategory.vue:10 +#: src/routes/modules/sites.ts:34 +#: src/views/site/site_category/SiteCategory.vue:10 msgid "Site Categories" msgstr "Categorías del sitio" -#: src/views/site/SiteAdd.vue:147 +#: src/views/site/site_add/SiteAdd.vue:147 #, fuzzy msgid "Site Config Created Successfully" msgstr "Configuración de dominio creada con éxito" @@ -2468,7 +2826,7 @@ msgstr "Configuración de dominio creada con éxito" msgid "Site is enabled" msgstr "Certificado automático" -#: src/routes/index.ts:224 +#: src/routes/modules/nginx_log.ts:31 msgid "Site Logs" msgstr "Registros del sitio" @@ -2482,7 +2840,7 @@ msgstr "Archivo no Encontrado" msgid "Sites Directory" msgstr "Directorio" -#: src/routes/index.ts:56 +#: src/routes/modules/sites.ts:19 msgid "Sites List" msgstr "Lista de sitios" @@ -2520,6 +2878,10 @@ msgstr "Acceso SSO" msgid "Stable" msgstr "Estable" +#: src/views/system/Backup/SystemRestore.vue:187 +msgid "Start Restore" +msgstr "" + #: src/views/certificate/ACMEUser.vue:65 #: src/views/certificate/CertificateList/certColumns.tsx:68 #: src/views/environment/envColumns.tsx:44 @@ -2572,6 +2934,10 @@ msgid "" "guide/nginx-proxy-example.html" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:140 +msgid "Supported file type: .zip" +msgstr "" + #: src/views/dashboard/ServerAnalytic.vue:236 #: src/views/dashboard/ServerAnalytic.vue:237 msgid "Swap" @@ -2629,7 +2995,7 @@ msgstr "Error de Configuración de Sincronización" msgid "Sync Config Success" msgstr "Configuración de sincronización exitosa" -#: src/views/site/site_category/SiteCategory.vue:17 +#: src/views/site/site_category/SiteCategory.vue:18 #, fuzzy msgid "Sync Nodes" msgstr "Sincronizar con" @@ -2648,20 +3014,30 @@ msgstr "Sincronizar con" msgid "Synchronization" msgstr "Sincronización" -#: src/routes/index.ts:275 +#: src/routes/modules/system.ts:11 msgid "System" msgstr "Sistema" +#: src/views/system/Backup/BackupCreator.vue:71 +#, fuzzy +msgid "System Backup" +msgstr "Sistema" + #: src/views/certificate/ACMEUserSelector.vue:88 msgid "System Initial User" msgstr "Usuario inicial del sistema" +#: src/views/system/Backup/SystemRestore.vue:117 +#, fuzzy +msgid "System Restore" +msgstr "Sistema" + #: src/constants/errors/self_check.ts:2 #, fuzzy msgid "Task not found" msgstr "Archivo no Encontrado" -#: src/routes/index.ts:194 src/views/terminal/Terminal.vue:114 +#: src/routes/modules/terminal.ts:10 src/views/terminal/Terminal.vue:114 msgid "Terminal" msgstr "Terminal" @@ -2724,7 +3100,7 @@ msgstr "" "El nombre del modelo solo debe contener letras, unicode, números, guiones, " "rayas y puntos." -#: src/views/site/SiteAdd.vue:120 +#: src/views/site/site_add/SiteAdd.vue:120 #, fuzzy msgid "The parameter of server_name is required" msgstr "Se requiere el parámetro server_name" @@ -2822,10 +3198,28 @@ msgstr "" "El nombre del modelo solo debe contener letras, unicode, números, guiones, " "rayas y puntos." +#: src/views/system/Backup/BackupCreator.vue:141 +msgid "" +"This token will only be shown once and cannot be retrieved later. Please " +"make sure to save it in a secure location." +msgstr "" + #: src/constants/form_errors.ts:4 msgid "This value is already taken" msgstr "Este valor ya está elegido" +#: src/views/system/Backup/SystemRestore.vue:169 +msgid "" +"This will restore all Nginx configuration files. Nginx will restart after " +"the restoration is complete." +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:180 +msgid "" +"This will restore configuration files and database. Nginx UI will restart " +"after the restoration is complete." +msgstr "" + #: src/views/environment/BatchUpgrader.vue:182 msgid "" "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}." @@ -2944,7 +3338,7 @@ msgstr "Actualizado a" msgid "Updated successfully" msgstr "Actualización exitosa" -#: src/routes/index.ts:297 src/views/environment/Environment.vue:66 +#: src/routes/modules/system.ts:40 src/views/environment/Environment.vue:66 #: src/views/system/Upgrade.vue:143 src/views/system/Upgrade.vue:226 msgid "Upgrade" msgstr "Actualizar" @@ -3008,6 +3402,10 @@ msgstr "Nombre de usuario (*)" msgid "Valid" msgstr "Válido" +#: src/views/system/Backup/SystemRestore.vue:159 +msgid "Verify Backup File Integrity" +msgstr "" + #: src/views/environment/envColumns.tsx:31 msgid "Version" msgstr "Versión" @@ -3042,10 +3440,18 @@ msgstr "Ver" #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33 #: src/views/notification/notificationColumns.tsx:22 #: src/views/preference/components/AddPasskey.vue:82 -#: src/views/site/SiteAdd.vue:115 +#: src/views/site/site_add/SiteAdd.vue:115 +#: src/views/system/Backup/BackupCreator.vue:138 msgid "Warning" msgstr "Advertencia" +#: src/views/system/Backup/SystemRestore.vue:121 +msgid "" +"Warning: Restore operation will overwrite current configurations. Make sure " +"you have a valid backup file and security token, and carefully select what " +"to restore." +msgstr "" + #: src/views/certificate/DNSCredential.vue:56 msgid "" "We will add one or more TXT records to the DNS records of your domain for " @@ -3155,6 +3561,10 @@ msgstr "" msgid "Your passkeys" msgstr "Sus llaves de acceso" +#, fuzzy +#~ msgid "Restart Required" +#~ msgstr "Reiniciando" + #~ msgid "Deploy %{conf_name} to %{node_name} successfully" #~ msgstr "Desplegado de %{conf_name} a %{node_name} exitoso" @@ -3189,9 +3599,6 @@ msgstr "Sus llaves de acceso" #~ msgid "Enable successfully" #~ msgstr "Habilitado con Éxito" -#~ msgid "Please select at least one node!" -#~ msgstr "¡Seleccione al menos un nodo!" - #, fuzzy #~ msgid "Please upgrade the remote Nginx UI to the latest version" #~ msgstr "" diff --git a/app/src/language/fr_FR/app.po b/app/src/language/fr_FR/app.po index 73ae26e8..b77e9aa7 100644 --- a/app/src/language/fr_FR/app.po +++ b/app/src/language/fr_FR/app.po @@ -22,15 +22,15 @@ msgstr "" msgid "2FA Settings" msgstr "Options 2FA" -#: src/routes/index.ts:290 +#: src/routes/modules/system.ts:26 msgid "About" msgstr "À propos" -#: src/routes/index.ts:210 src/views/site/ngx_conf/LogEntry.vue:75 +#: src/routes/modules/nginx_log.ts:17 src/views/site/ngx_conf/LogEntry.vue:75 msgid "Access Logs" msgstr "Journaux d'accès" -#: src/routes/index.ts:148 src/views/certificate/ACMEUser.vue:113 +#: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:113 #: src/views/certificate/ACMEUserSelector.vue:85 #, fuzzy msgid "ACME User" @@ -43,7 +43,7 @@ msgstr "Nom d'utilisateur" #: src/views/environment/envColumns.tsx:97 #: src/views/notification/notificationColumns.tsx:65 #: src/views/preference/AuthSettings.vue:30 -#: src/views/site/site_category/columns.ts:29 +#: src/views/site/site_category/columns.ts:28 #: src/views/site/site_list/columns.tsx:76 src/views/stream/StreamList.vue:49 #: src/views/user/userColumns.tsx:60 msgid "Action" @@ -64,7 +64,7 @@ msgstr "Ajouter" msgid "Add a passkey" msgstr "Ajouter une clé d'accès" -#: src/routes/index.ts:118 src/views/config/ConfigEditor.vue:144 +#: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:144 #: src/views/config/ConfigEditor.vue:204 #, fuzzy msgid "Add Configuration" @@ -79,7 +79,7 @@ msgstr "Ajouter une directive" msgid "Add Location" msgstr "Ajouter une localisation" -#: src/routes/index.ts:63 src/views/site/SiteAdd.vue:89 +#: src/routes/modules/sites.ts:26 src/views/site/site_add/SiteAdd.vue:89 msgid "Add Site" msgstr "Ajouter un site" @@ -269,6 +269,10 @@ msgstr "Renouvellement automatique désactivé pour %{name}" msgid "Auto-renewal enabled for %{name}" msgstr "Renouvellement automatique activé pour %{name}" +#: src/views/system/Backup/SystemRestore.vue:92 +msgid "Automatic Restart" +msgstr "" + #: src/views/certificate/CertificateEditor.vue:255 #: src/views/config/ConfigEditor.vue:213 src/views/config/ConfigList.vue:106 #: src/views/config/ConfigList.vue:180 src/views/nginx_log/NginxLog.vue:173 @@ -285,6 +289,25 @@ msgstr "Retour au menu principal" msgid "Back to list" msgstr "Retour à la liste" +#: src/routes/modules/system.ts:33 +#, fuzzy +msgid "Backup" +msgstr "Retour" + +#: src/views/system/Backup/SystemRestore.vue:100 +msgid "Backup file integrity check failed, it may have been tampered with" +msgstr "" + +#: src/constants/errors/backup.ts:39 +#, fuzzy +msgid "Backup file not found: {0}" +msgstr "Fichier introuvable" + +#: src/views/system/Backup/BackupCreator.vue:42 +#, fuzzy +msgid "Backup has been downloaded successfully" +msgstr "Nginx a été rechargé avec succès" + #: src/views/preference/AuthSettings.vue:129 msgid "Ban Threshold Minutes" msgstr "" @@ -297,7 +320,7 @@ msgstr "IPs bannies" msgid "Banned Until" msgstr "Banni durant" -#: src/views/site/SiteAdd.vue:95 +#: src/views/site/site_add/SiteAdd.vue:95 msgid "Base information" msgstr "Information générale" @@ -415,13 +438,13 @@ msgid_plural "Certificates Status" msgstr[0] "État du certificat" msgstr[1] "État du certificat" -#: src/routes/index.ts:139 +#: src/routes/modules/certificates.ts:11 #: src/views/certificate/CertificateList/Certificate.vue:13 #, fuzzy msgid "Certificates" msgstr "État du certificat" -#: src/routes/index.ts:156 +#: src/routes/modules/certificates.ts:28 #, fuzzy msgid "Certificates List" msgstr "Liste des certifications" @@ -499,6 +522,10 @@ msgstr "Effacer" msgid "Cleared successfully" msgstr "Désactivé avec succès" +#: src/views/system/Backup/SystemRestore.vue:137 +msgid "Click or drag backup file to this area to upload" +msgstr "" + #: src/views/preference/components/TOTP.vue:110 msgid "Click to copy" msgstr "Clique pour copier" @@ -515,6 +542,11 @@ msgstr "Commentaires" msgid "Comments" msgstr "Commentaires" +#: src/constants/errors/backup.ts:13 +#, fuzzy +msgid "Config path is empty" +msgstr "Modèles de configuration" + #: src/views/site/ngx_conf/config_template/ConfigTemplate.vue:84 msgid "Config Templates" msgstr "Modèles de configuration" @@ -523,7 +555,7 @@ msgstr "Modèles de configuration" msgid "Configuration file is test successful" msgstr "Le fichier de configuration est testé avec succès" -#: src/views/site/SiteAdd.vue:101 +#: src/views/site/site_add/SiteAdd.vue:101 msgid "Configuration Name" msgstr "Nom de la configuration" @@ -531,7 +563,7 @@ msgstr "Nom de la configuration" msgid "Configurations" msgstr "Configurations" -#: src/views/site/SiteAdd.vue:96 +#: src/views/site/site_add/SiteAdd.vue:96 msgid "Configure SSL" msgstr "Configurer SSL" @@ -555,7 +587,13 @@ msgstr "Contenu" msgid "Copied" msgstr "Copié" +#: src/views/system/Backup/BackupCreator.vue:128 +#, fuzzy +msgid "Copied!" +msgstr "Copié" + #: src/components/SensitiveString/SensitiveString.vue:37 +#: src/views/system/Backup/BackupCreator.vue:128 msgid "Copy" msgstr "Copier" @@ -580,10 +618,15 @@ msgstr "CPU :" msgid "Create" msgstr "Créé le" -#: src/views/site/SiteAdd.vue:157 +#: src/views/site/site_add/SiteAdd.vue:157 msgid "Create Another" msgstr "Créer un autre" +#: src/views/system/Backup/BackupCreator.vue:86 +#, fuzzy +msgid "Create Backup" +msgstr "Créé le" + #: src/views/config/ConfigList.vue:116 #, fuzzy msgid "Create File" @@ -594,9 +637,15 @@ msgstr "Créé le" msgid "Create Folder" msgstr "Créer un autre" +#: src/views/system/Backup/BackupCreator.vue:75 +msgid "" +"Create system backups including Nginx configuration and Nginx UI settings. " +"Backup files will be automatically downloaded to your computer." +msgstr "" + #: src/views/notification/notificationColumns.tsx:58 #: src/views/preference/components/Passkey.vue:95 -#: src/views/site/site_category/columns.ts:15 src/views/user/userColumns.tsx:48 +#: src/views/site/site_category/columns.ts:16 src/views/user/userColumns.tsx:48 msgid "Created at" msgstr "Créé le" @@ -642,7 +691,7 @@ msgid "" msgstr "" "Personnaliser le nom du nœud local affiché dans l'indicateur d'environnement" -#: src/routes/index.ts:38 src/views/config/ConfigEditor.vue:134 +#: src/routes/modules/dashboard.ts:10 src/views/config/ConfigEditor.vue:134 #: src/views/config/ConfigEditor.vue:97 src/views/config/ConfigList.vue:64 msgid "Dashboard" msgstr "Dashboard" @@ -840,7 +889,8 @@ msgstr "Désactivé avec succès" msgid "Disk IO" msgstr "E/S disque" -#: src/routes/index.ts:184 src/views/certificate/DNSCredential.vue:40 +#: src/routes/modules/certificates.ts:56 +#: src/views/certificate/DNSCredential.vue:40 msgid "DNS Credentials" msgstr "Identifiants DNS" @@ -957,15 +1007,15 @@ msgstr "Modifier %{n}" msgid "Edit %{n}" msgstr "Modifier %{n}" -#: src/routes/index.ts:128 src/views/config/ConfigEditor.vue:204 +#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:204 msgid "Edit Configuration" msgstr "Modifier la configuration" -#: src/routes/index.ts:78 +#: src/routes/modules/sites.ts:41 msgid "Edit Site" msgstr "Modifier le site" -#: src/routes/index.ts:98 +#: src/routes/modules/streams.ts:19 #, fuzzy msgid "Edit Stream" msgstr "Modifier le site" @@ -994,7 +1044,7 @@ msgstr "Activé avec succès" msgid "Enable auto-renewal failed for %{name}" msgstr "Échec de l'activation du renouvellement automatique pour %{name}" -#: src/views/site/SiteAdd.vue:43 +#: src/views/site/site_add/SiteAdd.vue:43 msgid "Enable failed" msgstr "Échec de l'activation" @@ -1060,8 +1110,9 @@ msgstr "Activer TLS" msgid "Enabled" msgstr "Activé" +#: src/views/site/site_add/SiteAdd.vue:40 #: src/views/site/site_edit/RightSettings.vue:33 -#: src/views/site/site_list/SiteList.vue:46 src/views/site/SiteAdd.vue:40 +#: src/views/site/site_list/SiteList.vue:46 #: src/views/stream/components/RightSettings.vue:29 #: src/views/stream/StreamList.vue:61 msgid "Enabled successfully" @@ -1076,7 +1127,8 @@ msgstr "Crypter le site Web avec Let's Encrypt" msgid "Environment variables cleaned" msgstr "Définition des variables d'environnement" -#: src/routes/index.ts:234 src/views/dashboard/Environments.vue:83 +#: src/routes/modules/environments.ts:11 +#: src/views/dashboard/Environments.vue:83 #: src/views/environment/Environment.vue:43 #, fuzzy msgid "Environments" @@ -1087,7 +1139,7 @@ msgstr "Commentaires" msgid "Error" msgstr "Erreur" -#: src/routes/index.ts:217 src/views/site/ngx_conf/LogEntry.vue:83 +#: src/routes/modules/nginx_log.ts:24 src/views/site/ngx_conf/LogEntry.vue:83 msgid "Error Logs" msgstr "Journaux d'erreurs" @@ -1114,11 +1166,131 @@ msgstr "Exporter" msgid "Fail to obtain certificate" msgstr "Obtenir un certificat" +#: src/constants/errors/backup.ts:5 +#, fuzzy +msgid "Failed to backup Nginx config files: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:4 +msgid "Failed to backup Nginx UI files: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:17 +#, fuzzy +msgid "Failed to calculate hash: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:53 +msgid "Failed to calculate Nginx hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:52 +msgid "Failed to calculate Nginx UI hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:14 +msgid "Failed to copy config file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:15 +msgid "Failed to copy database directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:16 +#, fuzzy +msgid "Failed to copy database file: {0}" +msgstr "Impossible de désactiver %{msg}" + +#: src/constants/errors/backup.ts:30 +msgid "Failed to copy file content: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:19 +msgid "Failed to copy Nginx config directory: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:9 #, fuzzy msgid "Failed to create backup" msgstr "Impossible d'activer %{msg}" +#: src/constants/errors/backup.ts:12 +#, fuzzy +msgid "Failed to create backup file: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:44 +#, fuzzy +msgid "Failed to create directory: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:46 +#, fuzzy +msgid "Failed to create file: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:6 +#, fuzzy +msgid "Failed to create hash info file: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:45 +#, fuzzy +msgid "Failed to create parent directory: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:32 +msgid "Failed to create restore directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:2 +#, fuzzy +msgid "Failed to create temporary directory" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:3 +#, fuzzy +msgid "Failed to create temporary subdirectory" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:9 +#, fuzzy +msgid "Failed to create zip archive: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:27 +#, fuzzy +msgid "Failed to create zip entry: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:26 +#, fuzzy +msgid "Failed to create zip file: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:29 +#, fuzzy +msgid "Failed to create zip header: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:24 +#, fuzzy +msgid "Failed to decrypt data: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:49 +#, fuzzy +msgid "Failed to decrypt file: {0}" +msgstr "Impossible de désactiver %{msg}" + +#: src/constants/errors/backup.ts:35 +msgid "Failed to decrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:34 +msgid "Failed to decrypt Nginx UI directory: {0}" +msgstr "" + #: src/views/site/site_edit/RightSettings.vue:45 #: src/views/site/site_list/SiteList.vue:60 #: src/views/stream/components/RightSettings.vue:41 @@ -1133,20 +1305,93 @@ msgstr "Impossible de désactiver %{msg}" msgid "Failed to enable %{msg}" msgstr "Impossible d'activer %{msg}" +#: src/constants/errors/backup.ts:23 +#, fuzzy +msgid "Failed to encrypt data: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:21 +#, fuzzy +msgid "Failed to encrypt file: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:8 +msgid "Failed to encrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:7 +msgid "Failed to encrypt Nginx UI directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:33 +#, fuzzy +msgid "Failed to extract archive: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:10 +#, fuzzy +msgid "Failed to generate AES key: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:11 +#, fuzzy +msgid "Failed to generate initialization vector: {0}" +msgstr "Échec de l'obtention des informations sur le certificat" + #: src/language/constants.ts:5 msgid "Failed to get certificate information" msgstr "Échec de l'obtention des informations sur le certificat" +#: src/constants/errors/backup.ts:28 +#, fuzzy +msgid "Failed to open source file: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:47 +#, fuzzy +msgid "Failed to open zip entry: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:43 +#, fuzzy +msgid "Failed to open zip file: {0}" +msgstr "Impossible d'activer %{msg}" + #: src/constants/errors/self_check.ts:4 #, fuzzy msgid "Failed to parse nginx.conf" msgstr "Erreur lecture nginx.conf" +#: src/constants/errors/backup.ts:48 +#, fuzzy +msgid "Failed to read encrypted file: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:20 +#, fuzzy +msgid "Failed to read file: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:51 +#, fuzzy +msgid "Failed to read hash info file: {0}" +msgstr "Impossible d'activer %{msg}" + #: src/constants/errors/self_check.ts:3 #, fuzzy msgid "Failed to read nginx.conf" msgstr "Impossible d'activer %{msg}" +#: src/constants/errors/backup.ts:37 +#, fuzzy +msgid "Failed to restore Nginx configs: {0}" +msgstr "Erreur lecture nginx.conf" + +#: src/constants/errors/backup.ts:38 +#, fuzzy +msgid "Failed to restore Nginx UI files: {0}" +msgstr "Erreur lecture nginx.conf" + #: src/views/site/site_edit/SiteEdit.vue:135 #: src/views/stream/StreamEdit.vue:122 msgid "Failed to save, syntax error(s) was detected in the configuration." @@ -1154,6 +1399,23 @@ msgstr "" "Échec de l'enregistrement, une ou plusieurs erreurs de syntaxe ont été " "détectées dans la configuration." +#: src/constants/errors/backup.ts:36 +#, fuzzy +msgid "Failed to verify hashes: {0}" +msgstr "Impossible d'activer %{msg}" + +#: src/constants/errors/backup.ts:50 +msgid "Failed to write decrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:22 +msgid "Failed to write encrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:31 +msgid "Failed to write to zip buffer: {0}" +msgstr "" + #: src/language/constants.ts:32 msgid "File exists" msgstr "Le fichier existe" @@ -1170,7 +1432,7 @@ msgstr "Nom du fichier vide" msgid "Filter" msgstr "Filtrer" -#: src/language/constants.ts:19 src/views/site/SiteAdd.vue:97 +#: src/language/constants.ts:19 src/views/site/site_add/SiteAdd.vue:97 msgid "Finished" msgstr "Finie" @@ -1248,11 +1510,15 @@ msgstr "Obtention du certificat, veuillez patienter..." msgid "Github Proxy" msgstr "Proxy Github" +#: src/constants/errors/backup.ts:54 +msgid "Hash verification failed: file integrity compromised" +msgstr "" + #: src/components/SensitiveString/SensitiveString.vue:40 msgid "Hide" msgstr "Cacher" -#: src/routes/index.ts:30 +#: src/routes/index.ts:47 msgid "Home" msgstr "Menu principal" @@ -1310,7 +1576,8 @@ msgstr "" msgid "Import" msgstr "Exporter" -#: src/routes/index.ts:174 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:46 +#: src/views/certificate/CertificateEditor.vue:85 #, fuzzy msgid "Import Certificate" msgstr "État du certificat" @@ -1336,7 +1603,7 @@ msgstr "Entrez le code de l'application :" msgid "Input the recovery code:" msgstr "Entrez le code de récupération :" -#: src/routes/index.ts:312 src/views/other/Install.vue:134 +#: src/routes/modules/auth.ts:8 src/views/other/Install.vue:134 msgid "Install" msgstr "Installer" @@ -1352,6 +1619,21 @@ msgstr "" msgid "Invalid" msgstr "Invalide" +#: src/constants/errors/backup.ts:42 +#, fuzzy +msgid "Invalid AES IV format: {0}" +msgstr "Format de la requête invalide" + +#: src/constants/errors/backup.ts:41 +#, fuzzy +msgid "Invalid AES key format: {0}" +msgstr "Format de la requête invalide" + +#: src/views/system/Backup/SystemRestore.vue:67 +#, fuzzy +msgid "Invalid file object" +msgstr "Nom de fichier invalide" + #: src/views/config/components/Rename.vue:64 #: src/views/config/ConfigEditor.vue:250 msgid "Invalid filename" @@ -1365,6 +1647,10 @@ msgstr "Nom du répertoire invalide" msgid "Invalid otp code" msgstr "Code otp invalide" +#: src/constants/errors/backup.ts:25 +msgid "Invalid padding in decrypted data" +msgstr "" + #: src/components/TwoFA/use2FAModal.ts:61 #, fuzzy msgid "Invalid passcode or recovery code" @@ -1378,6 +1664,11 @@ msgstr "Code de récupération invalide" msgid "Invalid request format" msgstr "Format de la requête invalide" +#: src/constants/errors/backup.ts:40 +#, fuzzy +msgid "Invalid security token format" +msgstr "Format de la requête invalide" + #: src/views/preference/AuthSettings.vue:18 msgid "IP" msgstr "" @@ -1508,7 +1799,7 @@ msgstr "Localisations" msgid "Log" msgstr "Connexion" -#: src/routes/index.ts:318 src/views/other/Login.vue:222 +#: src/routes/modules/auth.ts:14 src/views/other/Login.vue:222 msgid "Login" msgstr "Connexion" @@ -1543,21 +1834,21 @@ msgstr "" "Assurez vous d'avoir configuré un reverse proxy pour le répertoire .well-" "known vers HTTPChallengePort avant d'obtenir le certificat." -#: src/routes/index.ts:108 src/views/config/ConfigEditor.vue:102 +#: src/routes/modules/config.ts:10 src/views/config/ConfigEditor.vue:102 #: src/views/config/ConfigEditor.vue:139 src/views/config/ConfigList.vue:69 msgid "Manage Configs" msgstr "Gérer les configurations" -#: src/routes/index.ts:47 src/views/site/site_list/SiteList.vue:94 +#: src/routes/modules/sites.ts:10 src/views/site/site_list/SiteList.vue:94 msgid "Manage Sites" msgstr "Gérer les sites" -#: src/routes/index.ts:89 src/views/stream/StreamList.vue:119 +#: src/routes/modules/streams.ts:10 src/views/stream/StreamList.vue:119 #, fuzzy msgid "Manage Streams" msgstr "Gérer les sites" -#: src/routes/index.ts:257 src/views/user/User.vue:10 +#: src/routes/modules/user.ts:10 src/views/user/User.vue:10 msgid "Manage Users" msgstr "Gérer les utilisateurs" @@ -1595,12 +1886,13 @@ msgstr "Mode d'exécution" msgid "Modify" msgstr "Modifier" -#: src/routes/index.ts:164 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:36 +#: src/views/certificate/CertificateEditor.vue:85 #, fuzzy msgid "Modify Certificate" msgstr "État du certificat" -#: src/views/site/SiteAdd.vue:154 +#: src/views/site/site_add/SiteAdd.vue:154 msgid "Modify Config" msgstr "Modifier la configuration" @@ -1664,7 +1956,7 @@ msgstr "Nouvelle version publiée" #: src/views/certificate/WildcardCertificate.vue:91 #: src/views/site/cert/components/ObtainCert.vue:211 -#: src/views/site/SiteAdd.vue:141 +#: src/views/site/site_add/SiteAdd.vue:141 msgid "Next" msgstr "Suivant" @@ -1701,6 +1993,16 @@ msgstr "" msgid "Nginx conf not include stream-enabled" msgstr "" +#: src/constants/errors/backup.ts:18 +#, fuzzy +msgid "Nginx config directory is not set" +msgstr "Erreur d'analyse de configuration Nginx" + +#: src/views/system/Backup/SystemRestore.vue:84 +#, fuzzy +msgid "Nginx configuration has been restored" +msgstr "Erreur d'analyse de configuration Nginx" + #: src/views/site/site_edit/SiteEdit.vue:223 #: src/views/stream/StreamEdit.vue:208 msgid "Nginx Configuration Parse Error" @@ -1723,7 +2025,7 @@ msgstr "Chemin du journal des erreurs Nginx" msgid "Nginx is not running" msgstr "" -#: src/routes/index.ts:202 src/views/nginx_log/NginxLog.vue:148 +#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:148 msgid "Nginx Log" msgstr "Journal Nginx" @@ -1755,6 +2057,18 @@ msgstr "Commande de démarrage du terminal" msgid "Nginx restarted successfully" msgstr "Nginx a redémarré avec succès" +#: src/views/system/Backup/SystemRestore.vue:88 +#, fuzzy +msgid "Nginx UI configuration has been restored" +msgstr "Erreur d'analyse de configuration Nginx" + +#: src/views/system/Backup/SystemRestore.vue:93 +#, fuzzy +msgid "" +"Nginx UI configuration has been restored and will restart automatically in a " +"few seconds." +msgstr "Erreur d'analyse de configuration Nginx" + #: src/components/ChatGPT/ChatGPT.vue:374 #: src/components/Notification/Notification.vue:133 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:63 @@ -1786,7 +2100,7 @@ msgstr "Secret Jwt" msgid "Not After" msgstr "" -#: src/routes/index.ts:324 +#: src/routes/modules/error.ts:8 msgid "Not Found" msgstr "Introuvable" @@ -1810,7 +2124,8 @@ msgstr "" msgid "Notification" msgstr "Certification" -#: src/components/Notification/Notification.vue:131 src/routes/index.ts:248 +#: src/components/Notification/Notification.vue:131 +#: src/routes/modules/notifications.ts:10 #, fuzzy msgid "Notifications" msgstr "Certification" @@ -1859,6 +2174,8 @@ msgstr "" #: src/views/site/site_list/SiteList.vue:144 #: src/views/stream/components/RightSettings.vue:50 #: src/views/stream/StreamList.vue:164 +#: src/views/system/Backup/BackupCreator.vue:149 +#: src/views/system/Backup/SystemRestore.vue:94 msgid "OK" msgstr "OK" @@ -1873,6 +2190,10 @@ msgstr "" msgid "Online" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:24 +msgid "Only zip files are allowed" +msgstr "" + #: src/views/preference/Preference.vue:170 msgid "OpenAI" msgstr "OpenAI" @@ -1981,6 +2302,14 @@ msgstr "" msgid "Please enter the OTP code:" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:58 +msgid "Please enter the security token" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:153 +msgid "Please enter the security token received during backup" +msgstr "" + #: src/views/certificate/DNSCredential.vue:53 msgid "" "Please fill in the API authentication credentials provided by your DNS " @@ -2051,6 +2380,15 @@ msgid "" "Please note that the unit of time configurations below are all in seconds." msgstr "" +#: src/views/system/Backup/BackupCreator.vue:107 +msgid "Please save this security token, you will need it for restoration:" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:53 +#, fuzzy +msgid "Please select a backup file" +msgstr "Veuillez renseigner un nom de fichier" + #: src/views/environment/Environment.vue:58 msgid "Please select at least one node to upgrade" msgstr "" @@ -2061,7 +2399,7 @@ msgstr "" msgid "Pre-release" msgstr "" -#: src/routes/index.ts:266 src/views/preference/Preference.vue:141 +#: src/routes/modules/preference.ts:10 src/views/preference/Preference.vue:141 msgid "Preference" msgstr "Préférence" @@ -2348,6 +2686,21 @@ msgstr "Redémarrer" msgid "Restarting" msgstr "Redémarrage" +#: src/views/system/Backup/SystemRestore.vue:81 +#, fuzzy +msgid "Restore completed successfully" +msgstr "Désactivé avec succès" + +#: src/views/system/Backup/SystemRestore.vue:165 +#, fuzzy +msgid "Restore Nginx Configuration" +msgstr "Erreur d'analyse de configuration Nginx" + +#: src/views/system/Backup/SystemRestore.vue:176 +#, fuzzy +msgid "Restore Nginx UI Configuration" +msgstr "Erreur d'analyse de configuration Nginx" + #: src/views/preference/AuthSettings.vue:107 msgid "RP Display Name" msgstr "" @@ -2390,7 +2743,7 @@ msgstr "Enregistrer la directive" #: src/views/config/ConfigEditor.vue:171 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:41 -#: src/views/site/SiteAdd.vue:46 +#: src/views/site/site_add/SiteAdd.vue:46 msgid "Save error %{msg}" msgstr "Enregistrer l'erreur %{msg}" @@ -2443,7 +2796,8 @@ msgstr "Sauvegarde réussie" #: src/views/config/ConfigEditor.vue:167 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:39 -#: src/views/site/site_edit/SiteEdit.vue:152 src/views/site/SiteAdd.vue:37 +#: src/views/site/site_add/SiteAdd.vue:37 +#: src/views/site/site_edit/SiteEdit.vue:152 #: src/views/stream/StreamEdit.vue:139 msgid "Saved successfully" msgstr "Enregistré avec succès" @@ -2460,11 +2814,20 @@ msgstr "" msgid "Secret has been copied" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:150 +msgid "Security Token" +msgstr "" + +#: src/views/system/Backup/BackupCreator.vue:94 +#, fuzzy +msgid "Security Token Information" +msgstr "Format de la requête invalide" + #: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:189 msgid "Selector" msgstr "Sélecteur" -#: src/routes/index.ts:283 src/views/system/SelfCheck/SelfCheck.vue:42 +#: src/routes/modules/system.ts:19 src/views/system/SelfCheck/SelfCheck.vue:42 msgid "Self Check" msgstr "" @@ -2534,11 +2897,12 @@ msgstr "" msgid "Single Directive" msgstr "Directive unique" -#: src/routes/index.ts:71 src/views/site/site_category/SiteCategory.vue:10 +#: src/routes/modules/sites.ts:34 +#: src/views/site/site_category/SiteCategory.vue:10 msgid "Site Categories" msgstr "" -#: src/views/site/SiteAdd.vue:147 +#: src/views/site/site_add/SiteAdd.vue:147 #, fuzzy msgid "Site Config Created Successfully" msgstr "La configuration du domaine a été créée avec succès" @@ -2548,7 +2912,7 @@ msgstr "La configuration du domaine a été créée avec succès" msgid "Site is enabled" msgstr "Auto Cert" -#: src/routes/index.ts:224 +#: src/routes/modules/nginx_log.ts:31 msgid "Site Logs" msgstr "Journaux du site" @@ -2562,7 +2926,7 @@ msgstr "Fichier introuvable" msgid "Sites Directory" msgstr "Directive" -#: src/routes/index.ts:56 +#: src/routes/modules/sites.ts:19 msgid "Sites List" msgstr "Liste des sites" @@ -2606,6 +2970,10 @@ msgstr "Connexion" msgid "Stable" msgstr "Tableau" +#: src/views/system/Backup/SystemRestore.vue:187 +msgid "Start Restore" +msgstr "" + #: src/views/certificate/ACMEUser.vue:65 #: src/views/certificate/CertificateList/certColumns.tsx:68 #: src/views/environment/envColumns.tsx:44 @@ -2659,6 +3027,10 @@ msgid "" "guide/nginx-proxy-example.html" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:140 +msgid "Supported file type: .zip" +msgstr "" + #: src/views/dashboard/ServerAnalytic.vue:236 #: src/views/dashboard/ServerAnalytic.vue:237 #, fuzzy @@ -2723,7 +3095,7 @@ msgstr "Changer de certificat" msgid "Sync Config Success" msgstr "Changer de certificat" -#: src/views/site/site_category/SiteCategory.vue:17 +#: src/views/site/site_category/SiteCategory.vue:18 msgid "Sync Nodes" msgstr "" @@ -2742,20 +3114,30 @@ msgstr "Changer de certificat" msgid "Synchronization" msgstr "" -#: src/routes/index.ts:275 +#: src/routes/modules/system.ts:11 msgid "System" msgstr "Système" +#: src/views/system/Backup/BackupCreator.vue:71 +#, fuzzy +msgid "System Backup" +msgstr "Système" + #: src/views/certificate/ACMEUserSelector.vue:88 msgid "System Initial User" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:117 +#, fuzzy +msgid "System Restore" +msgstr "Système" + #: src/constants/errors/self_check.ts:2 #, fuzzy msgid "Task not found" msgstr "Fichier introuvable" -#: src/routes/index.ts:194 src/views/terminal/Terminal.vue:114 +#: src/routes/modules/terminal.ts:10 src/views/terminal/Terminal.vue:114 msgid "Terminal" msgstr "Terminal" @@ -2810,7 +3192,7 @@ msgid "" "dashes, colons, and dots." msgstr "" -#: src/views/site/SiteAdd.vue:120 +#: src/views/site/site_add/SiteAdd.vue:120 #, fuzzy msgid "The parameter of server_name is required" msgstr "Le paramètre server_name est obligatoire" @@ -2904,10 +3286,28 @@ msgid "" "This field should only contain letters, unicode characters, numbers, and -_." msgstr "" +#: src/views/system/Backup/BackupCreator.vue:141 +msgid "" +"This token will only be shown once and cannot be retrieved later. Please " +"make sure to save it in a secure location." +msgstr "" + #: src/constants/form_errors.ts:4 msgid "This value is already taken" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:169 +msgid "" +"This will restore all Nginx configuration files. Nginx will restart after " +"the restoration is complete." +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:180 +msgid "" +"This will restore configuration files and database. Nginx UI will restart " +"after the restoration is complete." +msgstr "" + #: src/views/environment/BatchUpgrader.vue:182 #, fuzzy msgid "" @@ -3014,7 +3414,7 @@ msgstr "Mis à jour le" msgid "Updated successfully" msgstr "Mis à jour avec succés" -#: src/routes/index.ts:297 src/views/environment/Environment.vue:66 +#: src/routes/modules/system.ts:40 src/views/environment/Environment.vue:66 #: src/views/system/Upgrade.vue:143 src/views/system/Upgrade.vue:226 msgid "Upgrade" msgstr "Mettre à niveau" @@ -3080,6 +3480,10 @@ msgstr "Nom d'utilisateur (*)" msgid "Valid" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:159 +msgid "Verify Backup File Integrity" +msgstr "" + #: src/views/environment/envColumns.tsx:31 #, fuzzy msgid "Version" @@ -3116,10 +3520,18 @@ msgstr "Voir" #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33 #: src/views/notification/notificationColumns.tsx:22 #: src/views/preference/components/AddPasskey.vue:82 -#: src/views/site/SiteAdd.vue:115 +#: src/views/site/site_add/SiteAdd.vue:115 +#: src/views/system/Backup/BackupCreator.vue:138 msgid "Warning" msgstr "Avertissement" +#: src/views/system/Backup/SystemRestore.vue:121 +msgid "" +"Warning: Restore operation will overwrite current configurations. Make sure " +"you have a valid backup file and security token, and carefully select what " +"to restore." +msgstr "" + #: src/views/certificate/DNSCredential.vue:56 msgid "" "We will add one or more TXT records to the DNS records of your domain for " @@ -3219,6 +3631,10 @@ msgstr "" msgid "Your passkeys" msgstr "" +#, fuzzy +#~ msgid "Restart Required" +#~ msgstr "Redémarrage" + #, fuzzy #~ msgid "Deploy %{conf_name} to %{node_name} successfully" #~ msgstr "Dupliqué avec succès" diff --git a/app/src/language/ko_KR/app.po b/app/src/language/ko_KR/app.po index 3fd6cc0c..ab043fd6 100644 --- a/app/src/language/ko_KR/app.po +++ b/app/src/language/ko_KR/app.po @@ -22,15 +22,15 @@ msgstr "2FA" msgid "2FA Settings" msgstr "2FA 설정" -#: src/routes/index.ts:290 +#: src/routes/modules/system.ts:26 msgid "About" msgstr "대하여" -#: src/routes/index.ts:210 src/views/site/ngx_conf/LogEntry.vue:75 +#: src/routes/modules/nginx_log.ts:17 src/views/site/ngx_conf/LogEntry.vue:75 msgid "Access Logs" msgstr "접근 로그" -#: src/routes/index.ts:148 src/views/certificate/ACMEUser.vue:113 +#: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:113 #: src/views/certificate/ACMEUserSelector.vue:85 msgid "ACME User" msgstr "ACME 사용자" @@ -42,7 +42,7 @@ msgstr "ACME 사용자" #: src/views/environment/envColumns.tsx:97 #: src/views/notification/notificationColumns.tsx:65 #: src/views/preference/AuthSettings.vue:30 -#: src/views/site/site_category/columns.ts:29 +#: src/views/site/site_category/columns.ts:28 #: src/views/site/site_list/columns.tsx:76 src/views/stream/StreamList.vue:49 #: src/views/user/userColumns.tsx:60 msgid "Action" @@ -63,7 +63,7 @@ msgstr "추가" msgid "Add a passkey" msgstr "" -#: src/routes/index.ts:118 src/views/config/ConfigEditor.vue:144 +#: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:144 #: src/views/config/ConfigEditor.vue:204 msgid "Add Configuration" msgstr "구성 추가" @@ -77,7 +77,7 @@ msgstr "아래에 지시문 추가" msgid "Add Location" msgstr "위치 추가" -#: src/routes/index.ts:63 src/views/site/SiteAdd.vue:89 +#: src/routes/modules/sites.ts:26 src/views/site/site_add/SiteAdd.vue:89 msgid "Add Site" msgstr "사이트 추가" @@ -254,6 +254,10 @@ msgstr "%{name}에 대한 자동 갱신 비활성화됨" msgid "Auto-renewal enabled for %{name}" msgstr "%{name}에 대한 자동 갱신 활성화됨" +#: src/views/system/Backup/SystemRestore.vue:92 +msgid "Automatic Restart" +msgstr "" + #: src/views/certificate/CertificateEditor.vue:255 #: src/views/config/ConfigEditor.vue:213 src/views/config/ConfigList.vue:106 #: src/views/config/ConfigList.vue:180 src/views/nginx_log/NginxLog.vue:173 @@ -270,6 +274,25 @@ msgstr "홈으로" msgid "Back to list" msgstr "목록으로 돌아가기" +#: src/routes/modules/system.ts:33 +#, fuzzy +msgid "Backup" +msgstr "뒤로" + +#: src/views/system/Backup/SystemRestore.vue:100 +msgid "Backup file integrity check failed, it may have been tampered with" +msgstr "" + +#: src/constants/errors/backup.ts:39 +#, fuzzy +msgid "Backup file not found: {0}" +msgstr "파일을 찾을 수 없음" + +#: src/views/system/Backup/BackupCreator.vue:42 +#, fuzzy +msgid "Backup has been downloaded successfully" +msgstr "Nginx가 성공적으로 리로드됨" + #: src/views/preference/AuthSettings.vue:129 msgid "Ban Threshold Minutes" msgstr "차단 시간(분)" @@ -282,7 +305,7 @@ msgstr "차단된 IP" msgid "Banned Until" msgstr "차단될 시간" -#: src/views/site/SiteAdd.vue:95 +#: src/views/site/site_add/SiteAdd.vue:95 msgid "Base information" msgstr "기본 정보" @@ -395,12 +418,12 @@ msgid_plural "Certificates Status" msgstr[0] "인증서 상태" msgstr[1] "인증서 상태" -#: src/routes/index.ts:139 +#: src/routes/modules/certificates.ts:11 #: src/views/certificate/CertificateList/Certificate.vue:13 msgid "Certificates" msgstr "인증서" -#: src/routes/index.ts:156 +#: src/routes/modules/certificates.ts:28 msgid "Certificates List" msgstr "인증서 목록" @@ -472,6 +495,10 @@ msgstr "클리어" msgid "Cleared successfully" msgstr "성공적으로 제거됨" +#: src/views/system/Backup/SystemRestore.vue:137 +msgid "Click or drag backup file to this area to upload" +msgstr "" + #: src/views/preference/components/TOTP.vue:110 msgid "Click to copy" msgstr "" @@ -487,6 +514,11 @@ msgstr "명령어" msgid "Comments" msgstr "댓글" +#: src/constants/errors/backup.ts:13 +#, fuzzy +msgid "Config path is empty" +msgstr "구성 템플릿" + #: src/views/site/ngx_conf/config_template/ConfigTemplate.vue:84 msgid "Config Templates" msgstr "구성 템플릿" @@ -495,7 +527,7 @@ msgstr "구성 템플릿" msgid "Configuration file is test successful" msgstr "구성 파일 테스트 성공" -#: src/views/site/SiteAdd.vue:101 +#: src/views/site/site_add/SiteAdd.vue:101 msgid "Configuration Name" msgstr "구성 이름" @@ -503,7 +535,7 @@ msgstr "구성 이름" msgid "Configurations" msgstr "구성들" -#: src/views/site/SiteAdd.vue:96 +#: src/views/site/site_add/SiteAdd.vue:96 msgid "Configure SSL" msgstr "SSL 구성하기" @@ -527,7 +559,12 @@ msgstr "내용" msgid "Copied" msgstr "" +#: src/views/system/Backup/BackupCreator.vue:128 +msgid "Copied!" +msgstr "" + #: src/components/SensitiveString/SensitiveString.vue:37 +#: src/views/system/Backup/BackupCreator.vue:128 msgid "Copy" msgstr "" @@ -551,10 +588,15 @@ msgstr "CPU:" msgid "Create" msgstr "생성" -#: src/views/site/SiteAdd.vue:157 +#: src/views/site/site_add/SiteAdd.vue:157 msgid "Create Another" msgstr "다른 것 생성하기" +#: src/views/system/Backup/BackupCreator.vue:86 +#, fuzzy +msgid "Create Backup" +msgstr "생성 시간" + #: src/views/config/ConfigList.vue:116 #, fuzzy msgid "Create File" @@ -565,9 +607,15 @@ msgstr "생성" msgid "Create Folder" msgstr "다른 것 생성하기" +#: src/views/system/Backup/BackupCreator.vue:75 +msgid "" +"Create system backups including Nginx configuration and Nginx UI settings. " +"Backup files will be automatically downloaded to your computer." +msgstr "" + #: src/views/notification/notificationColumns.tsx:58 #: src/views/preference/components/Passkey.vue:95 -#: src/views/site/site_category/columns.ts:15 src/views/user/userColumns.tsx:48 +#: src/views/site/site_category/columns.ts:16 src/views/user/userColumns.tsx:48 msgid "Created at" msgstr "생성 시간" @@ -611,7 +659,7 @@ msgid "" "indicator." msgstr "" -#: src/routes/index.ts:38 src/views/config/ConfigEditor.vue:134 +#: src/routes/modules/dashboard.ts:10 src/views/config/ConfigEditor.vue:134 #: src/views/config/ConfigEditor.vue:97 src/views/config/ConfigList.vue:64 msgid "Dashboard" msgstr "대시보드" @@ -805,7 +853,8 @@ msgstr "성공적으로 비활성화됨" msgid "Disk IO" msgstr "디스크 IO" -#: src/routes/index.ts:184 src/views/certificate/DNSCredential.vue:40 +#: src/routes/modules/certificates.ts:56 +#: src/views/certificate/DNSCredential.vue:40 msgid "DNS Credentials" msgstr "DNS 인증 정보" @@ -911,15 +960,15 @@ msgstr "%{n} 편집" msgid "Edit %{n}" msgstr "%{n} 편집" -#: src/routes/index.ts:128 src/views/config/ConfigEditor.vue:204 +#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:204 msgid "Edit Configuration" msgstr "구성 편집" -#: src/routes/index.ts:78 +#: src/routes/modules/sites.ts:41 msgid "Edit Site" msgstr "사이트 편집" -#: src/routes/index.ts:98 +#: src/routes/modules/streams.ts:19 msgid "Edit Stream" msgstr "스트림 편집" @@ -946,7 +995,7 @@ msgstr "성공적으로 활성화" msgid "Enable auto-renewal failed for %{name}" msgstr "%{name}에 대한 자동 갱신 활성화 실패" -#: src/views/site/SiteAdd.vue:43 +#: src/views/site/site_add/SiteAdd.vue:43 msgid "Enable failed" msgstr "활성화 실패" @@ -1012,8 +1061,9 @@ msgstr "TLS 활성화" msgid "Enabled" msgstr "활성화됨" +#: src/views/site/site_add/SiteAdd.vue:40 #: src/views/site/site_edit/RightSettings.vue:33 -#: src/views/site/site_list/SiteList.vue:46 src/views/site/SiteAdd.vue:40 +#: src/views/site/site_list/SiteList.vue:46 #: src/views/stream/components/RightSettings.vue:29 #: src/views/stream/StreamList.vue:61 msgid "Enabled successfully" @@ -1028,7 +1078,8 @@ msgstr "Let's Encrypt로 웹사이트 암호화" msgid "Environment variables cleaned" msgstr "환경 변수 설정" -#: src/routes/index.ts:234 src/views/dashboard/Environments.vue:83 +#: src/routes/modules/environments.ts:11 +#: src/views/dashboard/Environments.vue:83 #: src/views/environment/Environment.vue:43 msgid "Environments" msgstr "환경" @@ -1038,7 +1089,7 @@ msgstr "환경" msgid "Error" msgstr "오류" -#: src/routes/index.ts:217 src/views/site/ngx_conf/LogEntry.vue:83 +#: src/routes/modules/nginx_log.ts:24 src/views/site/ngx_conf/LogEntry.vue:83 msgid "Error Logs" msgstr "오류 로그" @@ -1065,11 +1116,130 @@ msgstr "내보내기" msgid "Fail to obtain certificate" msgstr "인증서 획득 실패" +#: src/constants/errors/backup.ts:5 +msgid "Failed to backup Nginx config files: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:4 +msgid "Failed to backup Nginx UI files: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:17 +#, fuzzy +msgid "Failed to calculate hash: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:53 +msgid "Failed to calculate Nginx hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:52 +msgid "Failed to calculate Nginx UI hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:14 +msgid "Failed to copy config file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:15 +msgid "Failed to copy database directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:16 +#, fuzzy +msgid "Failed to copy database file: {0}" +msgstr "%{msg} 비활성화 실패" + +#: src/constants/errors/backup.ts:30 +msgid "Failed to copy file content: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:19 +msgid "Failed to copy Nginx config directory: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:9 #, fuzzy msgid "Failed to create backup" msgstr "%{msg} 활성화 실패" +#: src/constants/errors/backup.ts:12 +#, fuzzy +msgid "Failed to create backup file: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:44 +#, fuzzy +msgid "Failed to create directory: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:46 +#, fuzzy +msgid "Failed to create file: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:6 +#, fuzzy +msgid "Failed to create hash info file: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:45 +#, fuzzy +msgid "Failed to create parent directory: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:32 +msgid "Failed to create restore directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:2 +#, fuzzy +msgid "Failed to create temporary directory" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:3 +#, fuzzy +msgid "Failed to create temporary subdirectory" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:9 +#, fuzzy +msgid "Failed to create zip archive: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:27 +#, fuzzy +msgid "Failed to create zip entry: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:26 +#, fuzzy +msgid "Failed to create zip file: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:29 +#, fuzzy +msgid "Failed to create zip header: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:24 +#, fuzzy +msgid "Failed to decrypt data: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:49 +#, fuzzy +msgid "Failed to decrypt file: {0}" +msgstr "%{msg} 비활성화 실패" + +#: src/constants/errors/backup.ts:35 +msgid "Failed to decrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:34 +msgid "Failed to decrypt Nginx UI directory: {0}" +msgstr "" + #: src/views/site/site_edit/RightSettings.vue:45 #: src/views/site/site_list/SiteList.vue:60 #: src/views/stream/components/RightSettings.vue:41 @@ -1084,23 +1254,109 @@ msgstr "%{msg} 비활성화 실패" msgid "Failed to enable %{msg}" msgstr "%{msg} 활성화 실패" +#: src/constants/errors/backup.ts:23 +#, fuzzy +msgid "Failed to encrypt data: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:21 +#, fuzzy +msgid "Failed to encrypt file: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:8 +msgid "Failed to encrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:7 +msgid "Failed to encrypt Nginx UI directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:33 +#, fuzzy +msgid "Failed to extract archive: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:10 +#, fuzzy +msgid "Failed to generate AES key: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:11 +#, fuzzy +msgid "Failed to generate initialization vector: {0}" +msgstr "인증서 정보 가져오기 실패" + #: src/language/constants.ts:5 msgid "Failed to get certificate information" msgstr "인증서 정보 가져오기 실패" +#: src/constants/errors/backup.ts:28 +#, fuzzy +msgid "Failed to open source file: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:47 +#, fuzzy +msgid "Failed to open zip entry: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:43 +#, fuzzy +msgid "Failed to open zip file: {0}" +msgstr "%{msg} 활성화 실패" + #: src/constants/errors/self_check.ts:4 msgid "Failed to parse nginx.conf" msgstr "" +#: src/constants/errors/backup.ts:48 +msgid "Failed to read encrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:20 +#, fuzzy +msgid "Failed to read file: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:51 +msgid "Failed to read hash info file: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:3 msgid "Failed to read nginx.conf" msgstr "" +#: src/constants/errors/backup.ts:37 +msgid "Failed to restore Nginx configs: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:38 +msgid "Failed to restore Nginx UI files: {0}" +msgstr "" + #: src/views/site/site_edit/SiteEdit.vue:135 #: src/views/stream/StreamEdit.vue:122 msgid "Failed to save, syntax error(s) was detected in the configuration." msgstr "저장 실패, 구성에서 구문 오류가 감지되었습니다." +#: src/constants/errors/backup.ts:36 +#, fuzzy +msgid "Failed to verify hashes: {0}" +msgstr "%{msg} 활성화 실패" + +#: src/constants/errors/backup.ts:50 +msgid "Failed to write decrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:22 +msgid "Failed to write encrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:31 +msgid "Failed to write to zip buffer: {0}" +msgstr "" + #: src/language/constants.ts:32 msgid "File exists" msgstr "파일이 존재함" @@ -1117,7 +1373,7 @@ msgstr "" msgid "Filter" msgstr "필터" -#: src/language/constants.ts:19 src/views/site/SiteAdd.vue:97 +#: src/language/constants.ts:19 src/views/site/site_add/SiteAdd.vue:97 msgid "Finished" msgstr "완료됨" @@ -1194,11 +1450,15 @@ msgstr "인증서를 가져오는 중입니다. 잠시 기다려 주세요..." msgid "Github Proxy" msgstr "Github 프록시" +#: src/constants/errors/backup.ts:54 +msgid "Hash verification failed: file integrity compromised" +msgstr "" + #: src/components/SensitiveString/SensitiveString.vue:40 msgid "Hide" msgstr "" -#: src/routes/index.ts:30 +#: src/routes/index.ts:47 msgid "Home" msgstr "홈" @@ -1246,7 +1506,8 @@ msgstr "" msgid "Import" msgstr "가져오기" -#: src/routes/index.ts:174 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:46 +#: src/views/certificate/CertificateEditor.vue:85 #, fuzzy msgid "Import Certificate" msgstr "인증서 상태" @@ -1272,7 +1533,7 @@ msgstr "" msgid "Input the recovery code:" msgstr "" -#: src/routes/index.ts:312 src/views/other/Install.vue:134 +#: src/routes/modules/auth.ts:8 src/views/other/Install.vue:134 msgid "Install" msgstr "설치" @@ -1290,6 +1551,19 @@ msgstr "간격" msgid "Invalid" msgstr "유효함" +#: src/constants/errors/backup.ts:42 +msgid "Invalid AES IV format: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:41 +msgid "Invalid AES key format: {0}" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:67 +#, fuzzy +msgid "Invalid file object" +msgstr "Invalid E-mail!" + #: src/views/config/components/Rename.vue:64 #: src/views/config/ConfigEditor.vue:250 #, fuzzy @@ -1305,6 +1579,10 @@ msgstr "" msgid "Invalid otp code" msgstr "유효함" +#: src/constants/errors/backup.ts:25 +msgid "Invalid padding in decrypted data" +msgstr "" + #: src/components/TwoFA/use2FAModal.ts:61 msgid "Invalid passcode or recovery code" msgstr "" @@ -1317,6 +1595,10 @@ msgstr "" msgid "Invalid request format" msgstr "" +#: src/constants/errors/backup.ts:40 +msgid "Invalid security token format" +msgstr "" + #: src/views/preference/AuthSettings.vue:18 msgid "IP" msgstr "" @@ -1443,7 +1725,7 @@ msgstr "위치들" msgid "Log" msgstr "로그인" -#: src/routes/index.ts:318 src/views/other/Login.vue:222 +#: src/routes/modules/auth.ts:14 src/views/other/Login.vue:222 msgid "Login" msgstr "로그인" @@ -1483,21 +1765,21 @@ msgstr "" "인증서를 획득하기 전에 .well-known 디렉토리에 대한역방향 프록시를 " "HTTPChallengePort(기본값: 9180)로 구성했는지 확인하세요." -#: src/routes/index.ts:108 src/views/config/ConfigEditor.vue:102 +#: src/routes/modules/config.ts:10 src/views/config/ConfigEditor.vue:102 #: src/views/config/ConfigEditor.vue:139 src/views/config/ConfigList.vue:69 msgid "Manage Configs" msgstr "구성 관리" -#: src/routes/index.ts:47 src/views/site/site_list/SiteList.vue:94 +#: src/routes/modules/sites.ts:10 src/views/site/site_list/SiteList.vue:94 msgid "Manage Sites" msgstr "사이트 관리" -#: src/routes/index.ts:89 src/views/stream/StreamList.vue:119 +#: src/routes/modules/streams.ts:10 src/views/stream/StreamList.vue:119 #, fuzzy msgid "Manage Streams" msgstr "스트림 관리" -#: src/routes/index.ts:257 src/views/user/User.vue:10 +#: src/routes/modules/user.ts:10 src/views/user/User.vue:10 msgid "Manage Users" msgstr "사용자 관리" @@ -1536,12 +1818,13 @@ msgstr "실행 모드" msgid "Modify" msgstr "설정 수정" -#: src/routes/index.ts:164 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:36 +#: src/views/certificate/CertificateEditor.vue:85 #, fuzzy msgid "Modify Certificate" msgstr "인증서 상태" -#: src/views/site/SiteAdd.vue:154 +#: src/views/site/site_add/SiteAdd.vue:154 msgid "Modify Config" msgstr "설정 수정" @@ -1606,7 +1889,7 @@ msgstr "새 버전 출시" #: src/views/certificate/WildcardCertificate.vue:91 #: src/views/site/cert/components/ObtainCert.vue:211 -#: src/views/site/SiteAdd.vue:141 +#: src/views/site/site_add/SiteAdd.vue:141 msgid "Next" msgstr "다음" @@ -1642,6 +1925,16 @@ msgstr "" msgid "Nginx conf not include stream-enabled" msgstr "" +#: src/constants/errors/backup.ts:18 +#, fuzzy +msgid "Nginx config directory is not set" +msgstr "Nginx 구성 오류름" + +#: src/views/system/Backup/SystemRestore.vue:84 +#, fuzzy +msgid "Nginx configuration has been restored" +msgstr "Nginx 구성 오류름" + #: src/views/site/site_edit/SiteEdit.vue:223 #: src/views/stream/StreamEdit.vue:208 #, fuzzy @@ -1665,7 +1958,7 @@ msgstr "Nginx 오류 로그 경로" msgid "Nginx is not running" msgstr "" -#: src/routes/index.ts:202 src/views/nginx_log/NginxLog.vue:148 +#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:148 msgid "Nginx Log" msgstr "Nginx 로그" @@ -1697,6 +1990,18 @@ msgstr "터미널 시작 명령" msgid "Nginx restarted successfully" msgstr "Nginx가 성공적으로 재시작됨" +#: src/views/system/Backup/SystemRestore.vue:88 +#, fuzzy +msgid "Nginx UI configuration has been restored" +msgstr "Nginx 구성 오류름" + +#: src/views/system/Backup/SystemRestore.vue:93 +#, fuzzy +msgid "" +"Nginx UI configuration has been restored and will restart automatically in a " +"few seconds." +msgstr "Nginx 구성 오류름" + #: src/components/ChatGPT/ChatGPT.vue:374 #: src/components/Notification/Notification.vue:133 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:63 @@ -1727,7 +2032,7 @@ msgstr "노드 시크릿" msgid "Not After" msgstr "만료일" -#: src/routes/index.ts:324 +#: src/routes/modules/error.ts:8 msgid "Not Found" msgstr "찾을 수 없음" @@ -1751,7 +2056,8 @@ msgstr "" msgid "Notification" msgstr "알림" -#: src/components/Notification/Notification.vue:131 src/routes/index.ts:248 +#: src/components/Notification/Notification.vue:131 +#: src/routes/modules/notifications.ts:10 #, fuzzy msgid "Notifications" msgstr "알림" @@ -1801,6 +2107,8 @@ msgstr "" #: src/views/site/site_list/SiteList.vue:144 #: src/views/stream/components/RightSettings.vue:50 #: src/views/stream/StreamList.vue:164 +#: src/views/system/Backup/BackupCreator.vue:149 +#: src/views/system/Backup/SystemRestore.vue:94 msgid "OK" msgstr "확인" @@ -1815,6 +2123,10 @@ msgstr "검증이 완료되면, 레코드는 제거됩니다." msgid "Online" msgstr "온라인" +#: src/views/system/Backup/SystemRestore.vue:24 +msgid "Only zip files are allowed" +msgstr "" + #: src/views/preference/Preference.vue:170 msgid "OpenAI" msgstr "오픈AI" @@ -1924,6 +2236,14 @@ msgstr "" msgid "Please enter the OTP code:" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:58 +msgid "Please enter the security token" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:153 +msgid "Please enter the security token received during backup" +msgstr "" + #: src/views/certificate/DNSCredential.vue:53 msgid "" "Please fill in the API authentication credentials provided by your DNS " @@ -1990,6 +2310,15 @@ msgid "" "Please note that the unit of time configurations below are all in seconds." msgstr "아래의 시간 설정 단위는 모두 초 단위임을 유의해주세요." +#: src/views/system/Backup/BackupCreator.vue:107 +msgid "Please save this security token, you will need it for restoration:" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:53 +#, fuzzy +msgid "Please select a backup file" +msgstr "적어도 하나의 노드를 선택해주세요!" + #: src/views/environment/Environment.vue:58 #, fuzzy msgid "Please select at least one node to upgrade" @@ -2001,7 +2330,7 @@ msgstr "적어도 하나의 노드를 선택해주세요!" msgid "Pre-release" msgstr "사전 출시" -#: src/routes/index.ts:266 src/views/preference/Preference.vue:141 +#: src/routes/modules/preference.ts:10 src/views/preference/Preference.vue:141 msgid "Preference" msgstr "환경설정" @@ -2287,6 +2616,21 @@ msgstr "재시작" msgid "Restarting" msgstr "재시작 중" +#: src/views/system/Backup/SystemRestore.vue:81 +#, fuzzy +msgid "Restore completed successfully" +msgstr "성공적으로 삭제됨" + +#: src/views/system/Backup/SystemRestore.vue:165 +#, fuzzy +msgid "Restore Nginx Configuration" +msgstr "Nginx 구성 오류름" + +#: src/views/system/Backup/SystemRestore.vue:176 +#, fuzzy +msgid "Restore Nginx UI Configuration" +msgstr "Nginx 구성 오류름" + #: src/views/preference/AuthSettings.vue:107 msgid "RP Display Name" msgstr "" @@ -2330,7 +2674,7 @@ msgstr "지시문 저장" #: src/views/config/ConfigEditor.vue:171 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:41 -#: src/views/site/SiteAdd.vue:46 +#: src/views/site/site_add/SiteAdd.vue:46 msgid "Save error %{msg}" msgstr "저장 오류 %{msg}" @@ -2384,7 +2728,8 @@ msgstr "성공적으로 저장됨" #: src/views/config/ConfigEditor.vue:167 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:39 -#: src/views/site/site_edit/SiteEdit.vue:152 src/views/site/SiteAdd.vue:37 +#: src/views/site/site_add/SiteAdd.vue:37 +#: src/views/site/site_edit/SiteEdit.vue:152 #: src/views/stream/StreamEdit.vue:139 msgid "Saved successfully" msgstr "성공적으로 저장됨" @@ -2401,11 +2746,19 @@ msgstr "" msgid "Secret has been copied" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:150 +msgid "Security Token" +msgstr "" + +#: src/views/system/Backup/BackupCreator.vue:94 +msgid "Security Token Information" +msgstr "" + #: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:189 msgid "Selector" msgstr "선택" -#: src/routes/index.ts:283 src/views/system/SelfCheck/SelfCheck.vue:42 +#: src/routes/modules/system.ts:19 src/views/system/SelfCheck/SelfCheck.vue:42 msgid "Self Check" msgstr "" @@ -2473,11 +2826,12 @@ msgstr "" msgid "Single Directive" msgstr "단일 지시문" -#: src/routes/index.ts:71 src/views/site/site_category/SiteCategory.vue:10 +#: src/routes/modules/sites.ts:34 +#: src/views/site/site_category/SiteCategory.vue:10 msgid "Site Categories" msgstr "" -#: src/views/site/SiteAdd.vue:147 +#: src/views/site/site_add/SiteAdd.vue:147 #, fuzzy msgid "Site Config Created Successfully" msgstr "도메인 구성이 성공적으로 생성되었습니다" @@ -2487,7 +2841,7 @@ msgstr "도메인 구성이 성공적으로 생성되었습니다" msgid "Site is enabled" msgstr "비활성화됨" -#: src/routes/index.ts:224 +#: src/routes/modules/nginx_log.ts:31 #, fuzzy msgid "Site Logs" msgstr "사이트 로그" @@ -2502,7 +2856,7 @@ msgstr "파일을 찾을 수 없음" msgid "Sites Directory" msgstr "디렉토리" -#: src/routes/index.ts:56 +#: src/routes/modules/sites.ts:19 msgid "Sites List" msgstr "사이트 목록" @@ -2545,6 +2899,10 @@ msgstr "SSO 로그인" msgid "Stable" msgstr "활성화됨" +#: src/views/system/Backup/SystemRestore.vue:187 +msgid "Start Restore" +msgstr "" + #: src/views/certificate/ACMEUser.vue:65 #: src/views/certificate/CertificateList/certColumns.tsx:68 #: src/views/environment/envColumns.tsx:44 @@ -2597,6 +2955,10 @@ msgid "" "guide/nginx-proxy-example.html" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:140 +msgid "Supported file type: .zip" +msgstr "" + #: src/views/dashboard/ServerAnalytic.vue:236 #: src/views/dashboard/ServerAnalytic.vue:237 msgid "Swap" @@ -2660,7 +3022,7 @@ msgstr "인증서 갱신 오류" msgid "Sync Config Success" msgstr "인증서 갱신 성공" -#: src/views/site/site_category/SiteCategory.vue:17 +#: src/views/site/site_category/SiteCategory.vue:18 msgid "Sync Nodes" msgstr "" @@ -2678,20 +3040,30 @@ msgstr "" msgid "Synchronization" msgstr "" -#: src/routes/index.ts:275 +#: src/routes/modules/system.ts:11 msgid "System" msgstr "시스템" +#: src/views/system/Backup/BackupCreator.vue:71 +#, fuzzy +msgid "System Backup" +msgstr "시스템" + #: src/views/certificate/ACMEUserSelector.vue:88 msgid "System Initial User" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:117 +#, fuzzy +msgid "System Restore" +msgstr "시스템" + #: src/constants/errors/self_check.ts:2 #, fuzzy msgid "Task not found" msgstr "파일을 찾을 수 없음" -#: src/routes/index.ts:194 src/views/terminal/Terminal.vue:114 +#: src/routes/modules/terminal.ts:10 src/views/terminal/Terminal.vue:114 msgid "Terminal" msgstr "터미널" @@ -2745,7 +3117,7 @@ msgid "" "dashes, colons, and dots." msgstr "" -#: src/views/site/SiteAdd.vue:120 +#: src/views/site/site_add/SiteAdd.vue:120 #, fuzzy msgid "The parameter of server_name is required" msgstr "server_name 매개변수가 필요합니다" @@ -2838,10 +3210,28 @@ msgid "" "This field should only contain letters, unicode characters, numbers, and -_." msgstr "" +#: src/views/system/Backup/BackupCreator.vue:141 +msgid "" +"This token will only be shown once and cannot be retrieved later. Please " +"make sure to save it in a secure location." +msgstr "" + #: src/constants/form_errors.ts:4 msgid "This value is already taken" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:169 +msgid "" +"This will restore all Nginx configuration files. Nginx will restart after " +"the restoration is complete." +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:180 +msgid "" +"This will restore configuration files and database. Nginx UI will restart " +"after the restoration is complete." +msgstr "" + #: src/views/environment/BatchUpgrader.vue:182 msgid "" "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}." @@ -2947,7 +3337,7 @@ msgstr "업데이트됨" msgid "Updated successfully" msgstr "성공적으로 저장되었습니다" -#: src/routes/index.ts:297 src/views/environment/Environment.vue:66 +#: src/routes/modules/system.ts:40 src/views/environment/Environment.vue:66 #: src/views/system/Upgrade.vue:143 src/views/system/Upgrade.vue:226 msgid "Upgrade" msgstr "업그레이드" @@ -3014,6 +3404,10 @@ msgstr "사용자 이름 (*)" msgid "Valid" msgstr "유효함" +#: src/views/system/Backup/SystemRestore.vue:159 +msgid "Verify Backup File Integrity" +msgstr "" + #: src/views/environment/envColumns.tsx:31 #, fuzzy msgid "Version" @@ -3051,10 +3445,18 @@ msgstr "보기" #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33 #: src/views/notification/notificationColumns.tsx:22 #: src/views/preference/components/AddPasskey.vue:82 -#: src/views/site/SiteAdd.vue:115 +#: src/views/site/site_add/SiteAdd.vue:115 +#: src/views/system/Backup/BackupCreator.vue:138 msgid "Warning" msgstr "경고" +#: src/views/system/Backup/SystemRestore.vue:121 +msgid "" +"Warning: Restore operation will overwrite current configurations. Make sure " +"you have a valid backup file and security token, and carefully select what " +"to restore." +msgstr "" + #: src/views/certificate/DNSCredential.vue:56 msgid "" "We will add one or more TXT records to the DNS records of your domain for " @@ -3156,6 +3558,10 @@ msgstr "" msgid "Your passkeys" msgstr "" +#, fuzzy +#~ msgid "Restart Required" +#~ msgstr "재시작 중" + #~ msgid "Deploy %{conf_name} to %{node_name} successfully" #~ msgstr "%{conf_name}을(를) %{node_name}(으)로 배포 성공" @@ -3191,9 +3597,6 @@ msgstr "" #~ msgid "Enable successfully" #~ msgstr "성공적으로 활성화" -#~ msgid "Please select at least one node!" -#~ msgstr "적어도 하나의 노드를 선택해주세요!" - #, fuzzy #~ msgid "Please upgrade the remote Nginx UI to the latest version" #~ msgstr "%{conf_name}을(를) %{node_name}(으)로 성공적으로 복제함" diff --git a/app/src/language/messages.pot b/app/src/language/messages.pot index 5059b1dd..70350ee5 100644 --- a/app/src/language/messages.pot +++ b/app/src/language/messages.pot @@ -10,16 +10,16 @@ msgstr "" msgid "2FA Settings" msgstr "" -#: src/routes/index.ts:290 +#: src/routes/modules/system.ts:26 msgid "About" msgstr "" -#: src/routes/index.ts:210 +#: src/routes/modules/nginx_log.ts:17 #: src/views/site/ngx_conf/LogEntry.vue:75 msgid "Access Logs" msgstr "" -#: src/routes/index.ts:148 +#: src/routes/modules/certificates.ts:20 #: src/views/certificate/ACMEUser.vue:113 #: src/views/certificate/ACMEUserSelector.vue:85 msgid "ACME User" @@ -32,7 +32,7 @@ msgstr "" #: src/views/environment/envColumns.tsx:97 #: src/views/notification/notificationColumns.tsx:65 #: src/views/preference/AuthSettings.vue:30 -#: src/views/site/site_category/columns.ts:29 +#: src/views/site/site_category/columns.ts:28 #: src/views/site/site_list/columns.tsx:76 #: src/views/stream/StreamList.vue:49 #: src/views/user/userColumns.tsx:60 @@ -54,7 +54,7 @@ msgstr "" msgid "Add a passkey" msgstr "" -#: src/routes/index.ts:118 +#: src/routes/modules/config.ts:20 #: src/views/config/ConfigEditor.vue:144 #: src/views/config/ConfigEditor.vue:204 msgid "Add Configuration" @@ -69,8 +69,8 @@ msgstr "" msgid "Add Location" msgstr "" -#: src/routes/index.ts:63 -#: src/views/site/SiteAdd.vue:89 +#: src/routes/modules/sites.ts:26 +#: src/views/site/site_add/SiteAdd.vue:89 msgid "Add Site" msgstr "" @@ -240,6 +240,10 @@ msgstr "" msgid "Auto-renewal enabled for %{name}" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:92 +msgid "Automatic Restart" +msgstr "" + #: src/views/certificate/CertificateEditor.vue:255 #: src/views/config/ConfigEditor.vue:213 #: src/views/config/ConfigList.vue:106 @@ -258,6 +262,22 @@ msgstr "" msgid "Back to list" msgstr "" +#: src/routes/modules/system.ts:33 +msgid "Backup" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:100 +msgid "Backup file integrity check failed, it may have been tampered with" +msgstr "" + +#: src/constants/errors/backup.ts:39 +msgid "Backup file not found: {0}" +msgstr "" + +#: src/views/system/Backup/BackupCreator.vue:42 +msgid "Backup has been downloaded successfully" +msgstr "" + #: src/views/preference/AuthSettings.vue:129 msgid "Ban Threshold Minutes" msgstr "" @@ -270,7 +290,7 @@ msgstr "" msgid "Banned Until" msgstr "" -#: src/views/site/SiteAdd.vue:95 +#: src/views/site/site_add/SiteAdd.vue:95 msgid "Base information" msgstr "" @@ -377,12 +397,12 @@ msgid_plural "Certificates Status" msgstr[0] "" msgstr[1] "" -#: src/routes/index.ts:139 +#: src/routes/modules/certificates.ts:11 #: src/views/certificate/CertificateList/Certificate.vue:13 msgid "Certificates" msgstr "" -#: src/routes/index.ts:156 +#: src/routes/modules/certificates.ts:28 msgid "Certificates List" msgstr "" @@ -449,6 +469,10 @@ msgstr "" msgid "Cleared successfully" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:137 +msgid "Click or drag backup file to this area to upload" +msgstr "" + #: src/views/preference/components/TOTP.vue:110 msgid "Click to copy" msgstr "" @@ -464,6 +488,10 @@ msgstr "" msgid "Comments" msgstr "" +#: src/constants/errors/backup.ts:13 +msgid "Config path is empty" +msgstr "" + #: src/views/site/ngx_conf/config_template/ConfigTemplate.vue:84 msgid "Config Templates" msgstr "" @@ -472,7 +500,7 @@ msgstr "" msgid "Configuration file is test successful" msgstr "" -#: src/views/site/SiteAdd.vue:101 +#: src/views/site/site_add/SiteAdd.vue:101 msgid "Configuration Name" msgstr "" @@ -480,7 +508,7 @@ msgstr "" msgid "Configurations" msgstr "" -#: src/views/site/SiteAdd.vue:96 +#: src/views/site/site_add/SiteAdd.vue:96 msgid "Configure SSL" msgstr "" @@ -504,7 +532,12 @@ msgstr "" msgid "Copied" msgstr "" +#: src/views/system/Backup/BackupCreator.vue:128 +msgid "Copied!" +msgstr "" + #: src/components/SensitiveString/SensitiveString.vue:37 +#: src/views/system/Backup/BackupCreator.vue:128 msgid "Copy" msgstr "" @@ -528,10 +561,14 @@ msgstr "" msgid "Create" msgstr "" -#: src/views/site/SiteAdd.vue:157 +#: src/views/site/site_add/SiteAdd.vue:157 msgid "Create Another" msgstr "" +#: src/views/system/Backup/BackupCreator.vue:86 +msgid "Create Backup" +msgstr "" + #: src/views/config/ConfigList.vue:116 msgid "Create File" msgstr "" @@ -541,9 +578,13 @@ msgstr "" msgid "Create Folder" msgstr "" +#: src/views/system/Backup/BackupCreator.vue:75 +msgid "Create system backups including Nginx configuration and Nginx UI settings. Backup files will be automatically downloaded to your computer." +msgstr "" + #: src/views/notification/notificationColumns.tsx:58 #: src/views/preference/components/Passkey.vue:95 -#: src/views/site/site_category/columns.ts:15 +#: src/views/site/site_category/columns.ts:16 #: src/views/user/userColumns.tsx:48 msgid "Created at" msgstr "" @@ -585,7 +626,7 @@ msgstr "" msgid "Customize the name of local node to be displayed in the environment indicator." msgstr "" -#: src/routes/index.ts:38 +#: src/routes/modules/dashboard.ts:10 #: src/views/config/ConfigEditor.vue:134 #: src/views/config/ConfigEditor.vue:97 #: src/views/config/ConfigList.vue:64 @@ -771,7 +812,7 @@ msgstr "" msgid "Disk IO" msgstr "" -#: src/routes/index.ts:184 +#: src/routes/modules/certificates.ts:56 #: src/views/certificate/DNSCredential.vue:40 msgid "DNS Credentials" msgstr "" @@ -874,16 +915,16 @@ msgstr "" msgid "Edit %{n}" msgstr "" -#: src/routes/index.ts:128 +#: src/routes/modules/config.ts:30 #: src/views/config/ConfigEditor.vue:204 msgid "Edit Configuration" msgstr "" -#: src/routes/index.ts:78 +#: src/routes/modules/sites.ts:41 msgid "Edit Site" msgstr "" -#: src/routes/index.ts:98 +#: src/routes/modules/streams.ts:19 msgid "Edit Stream" msgstr "" @@ -908,7 +949,7 @@ msgstr "" msgid "Enable auto-renewal failed for %{name}" msgstr "" -#: src/views/site/SiteAdd.vue:43 +#: src/views/site/site_add/SiteAdd.vue:43 msgid "Enable failed" msgstr "" @@ -968,9 +1009,9 @@ msgstr "" msgid "Enabled" msgstr "" +#: src/views/site/site_add/SiteAdd.vue:40 #: src/views/site/site_edit/RightSettings.vue:33 #: src/views/site/site_list/SiteList.vue:46 -#: src/views/site/SiteAdd.vue:40 #: src/views/stream/components/RightSettings.vue:29 #: src/views/stream/StreamList.vue:61 msgid "Enabled successfully" @@ -984,7 +1025,7 @@ msgstr "" msgid "Environment variables cleaned" msgstr "" -#: src/routes/index.ts:234 +#: src/routes/modules/environments.ts:11 #: src/views/dashboard/Environments.vue:83 #: src/views/environment/Environment.vue:43 msgid "Environments" @@ -996,7 +1037,7 @@ msgstr "" msgid "Error" msgstr "" -#: src/routes/index.ts:217 +#: src/routes/modules/nginx_log.ts:24 #: src/views/site/ngx_conf/LogEntry.vue:83 msgid "Error Logs" msgstr "" @@ -1022,10 +1063,114 @@ msgstr "" msgid "Fail to obtain certificate" msgstr "" +#: src/constants/errors/backup.ts:5 +msgid "Failed to backup Nginx config files: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:4 +msgid "Failed to backup Nginx UI files: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:17 +msgid "Failed to calculate hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:53 +msgid "Failed to calculate Nginx hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:52 +msgid "Failed to calculate Nginx UI hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:14 +msgid "Failed to copy config file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:15 +msgid "Failed to copy database directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:16 +msgid "Failed to copy database file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:30 +msgid "Failed to copy file content: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:19 +msgid "Failed to copy Nginx config directory: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:9 msgid "Failed to create backup" msgstr "" +#: src/constants/errors/backup.ts:12 +msgid "Failed to create backup file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:44 +msgid "Failed to create directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:46 +msgid "Failed to create file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:6 +msgid "Failed to create hash info file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:45 +msgid "Failed to create parent directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:32 +msgid "Failed to create restore directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:2 +msgid "Failed to create temporary directory" +msgstr "" + +#: src/constants/errors/backup.ts:3 +msgid "Failed to create temporary subdirectory" +msgstr "" + +#: src/constants/errors/backup.ts:9 +msgid "Failed to create zip archive: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:27 +msgid "Failed to create zip entry: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:26 +msgid "Failed to create zip file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:29 +msgid "Failed to create zip header: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:24 +msgid "Failed to decrypt data: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:49 +msgid "Failed to decrypt file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:35 +msgid "Failed to decrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:34 +msgid "Failed to decrypt Nginx UI directory: {0}" +msgstr "" + #: src/views/site/site_edit/RightSettings.vue:45 #: src/views/site/site_list/SiteList.vue:60 #: src/views/stream/components/RightSettings.vue:41 @@ -1040,23 +1185,99 @@ msgstr "" msgid "Failed to enable %{msg}" msgstr "" +#: src/constants/errors/backup.ts:23 +msgid "Failed to encrypt data: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:21 +msgid "Failed to encrypt file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:8 +msgid "Failed to encrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:7 +msgid "Failed to encrypt Nginx UI directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:33 +msgid "Failed to extract archive: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:10 +msgid "Failed to generate AES key: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:11 +msgid "Failed to generate initialization vector: {0}" +msgstr "" + #: src/language/constants.ts:5 msgid "Failed to get certificate information" msgstr "" +#: src/constants/errors/backup.ts:28 +msgid "Failed to open source file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:47 +msgid "Failed to open zip entry: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:43 +msgid "Failed to open zip file: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:4 msgid "Failed to parse nginx.conf" msgstr "" +#: src/constants/errors/backup.ts:48 +msgid "Failed to read encrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:20 +msgid "Failed to read file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:51 +msgid "Failed to read hash info file: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:3 msgid "Failed to read nginx.conf" msgstr "" +#: src/constants/errors/backup.ts:37 +msgid "Failed to restore Nginx configs: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:38 +msgid "Failed to restore Nginx UI files: {0}" +msgstr "" + #: src/views/site/site_edit/SiteEdit.vue:135 #: src/views/stream/StreamEdit.vue:122 msgid "Failed to save, syntax error(s) was detected in the configuration." msgstr "" +#: src/constants/errors/backup.ts:36 +msgid "Failed to verify hashes: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:50 +msgid "Failed to write decrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:22 +msgid "Failed to write encrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:31 +msgid "Failed to write to zip buffer: {0}" +msgstr "" + #: src/language/constants.ts:32 msgid "File exists" msgstr "" @@ -1074,7 +1295,7 @@ msgid "Filter" msgstr "" #: src/language/constants.ts:19 -#: src/views/site/SiteAdd.vue:97 +#: src/views/site/site_add/SiteAdd.vue:97 msgid "Finished" msgstr "" @@ -1145,11 +1366,15 @@ msgstr "" msgid "Github Proxy" msgstr "" +#: src/constants/errors/backup.ts:54 +msgid "Hash verification failed: file integrity compromised" +msgstr "" + #: src/components/SensitiveString/SensitiveString.vue:40 msgid "Hide" msgstr "" -#: src/routes/index.ts:30 +#: src/routes/index.ts:47 msgid "Home" msgstr "" @@ -1193,7 +1418,7 @@ msgstr "" msgid "Import" msgstr "" -#: src/routes/index.ts:174 +#: src/routes/modules/certificates.ts:46 #: src/views/certificate/CertificateEditor.vue:85 msgid "Import Certificate" msgstr "" @@ -1220,7 +1445,7 @@ msgstr "" msgid "Input the recovery code:" msgstr "" -#: src/routes/index.ts:312 +#: src/routes/modules/auth.ts:8 #: src/views/other/Install.vue:134 msgid "Install" msgstr "" @@ -1237,6 +1462,18 @@ msgstr "" msgid "Invalid" msgstr "" +#: src/constants/errors/backup.ts:42 +msgid "Invalid AES IV format: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:41 +msgid "Invalid AES key format: {0}" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:67 +msgid "Invalid file object" +msgstr "" + #: src/views/config/components/Rename.vue:64 #: src/views/config/ConfigEditor.vue:250 msgid "Invalid filename" @@ -1250,6 +1487,10 @@ msgstr "" msgid "Invalid otp code" msgstr "" +#: src/constants/errors/backup.ts:25 +msgid "Invalid padding in decrypted data" +msgstr "" + #: src/components/TwoFA/use2FAModal.ts:61 msgid "Invalid passcode or recovery code" msgstr "" @@ -1262,6 +1503,10 @@ msgstr "" msgid "Invalid request format" msgstr "" +#: src/constants/errors/backup.ts:40 +msgid "Invalid security token format" +msgstr "" + #: src/views/preference/AuthSettings.vue:18 msgid "IP" msgstr "" @@ -1374,7 +1619,7 @@ msgstr "" msgid "Log" msgstr "" -#: src/routes/index.ts:318 +#: src/routes/modules/auth.ts:14 #: src/views/other/Login.vue:222 msgid "Login" msgstr "" @@ -1400,24 +1645,24 @@ msgstr "" msgid "Make sure you have configured a reverse proxy for .well-known directory to HTTPChallengePort before obtaining the certificate." msgstr "" -#: src/routes/index.ts:108 +#: src/routes/modules/config.ts:10 #: src/views/config/ConfigEditor.vue:102 #: src/views/config/ConfigEditor.vue:139 #: src/views/config/ConfigList.vue:69 msgid "Manage Configs" msgstr "" -#: src/routes/index.ts:47 +#: src/routes/modules/sites.ts:10 #: src/views/site/site_list/SiteList.vue:94 msgid "Manage Sites" msgstr "" -#: src/routes/index.ts:89 +#: src/routes/modules/streams.ts:10 #: src/views/stream/StreamList.vue:119 msgid "Manage Streams" msgstr "" -#: src/routes/index.ts:257 +#: src/routes/modules/user.ts:10 #: src/views/user/User.vue:10 msgid "Manage Users" msgstr "" @@ -1454,12 +1699,12 @@ msgstr "" msgid "Modify" msgstr "" -#: src/routes/index.ts:164 +#: src/routes/modules/certificates.ts:36 #: src/views/certificate/CertificateEditor.vue:85 msgid "Modify Certificate" msgstr "" -#: src/views/site/SiteAdd.vue:154 +#: src/views/site/site_add/SiteAdd.vue:154 msgid "Modify Config" msgstr "" @@ -1522,7 +1767,7 @@ msgstr "" #: src/views/certificate/WildcardCertificate.vue:91 #: src/views/site/cert/components/ObtainCert.vue:211 -#: src/views/site/SiteAdd.vue:141 +#: src/views/site/site_add/SiteAdd.vue:141 msgid "Next" msgstr "" @@ -1558,6 +1803,14 @@ msgstr "" msgid "Nginx conf not include stream-enabled" msgstr "" +#: src/constants/errors/backup.ts:18 +msgid "Nginx config directory is not set" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:84 +msgid "Nginx configuration has been restored" +msgstr "" + #: src/views/site/site_edit/SiteEdit.vue:223 #: src/views/stream/StreamEdit.vue:208 msgid "Nginx Configuration Parse Error" @@ -1579,7 +1832,7 @@ msgstr "" msgid "Nginx is not running" msgstr "" -#: src/routes/index.ts:202 +#: src/routes/modules/nginx_log.ts:9 #: src/views/nginx_log/NginxLog.vue:148 msgid "Nginx Log" msgstr "" @@ -1608,6 +1861,14 @@ msgstr "" msgid "Nginx restarted successfully" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:88 +msgid "Nginx UI configuration has been restored" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:93 +msgid "Nginx UI configuration has been restored and will restart automatically in a few seconds." +msgstr "" + #: src/components/ChatGPT/ChatGPT.vue:374 #: src/components/Notification/Notification.vue:133 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:63 @@ -1637,7 +1898,7 @@ msgstr "" msgid "Not After" msgstr "" -#: src/routes/index.ts:324 +#: src/routes/modules/error.ts:8 msgid "Not Found" msgstr "" @@ -1659,7 +1920,7 @@ msgid "Notification" msgstr "" #: src/components/Notification/Notification.vue:131 -#: src/routes/index.ts:248 +#: src/routes/modules/notifications.ts:10 msgid "Notifications" msgstr "" @@ -1705,6 +1966,8 @@ msgstr "" #: src/views/site/site_list/SiteList.vue:144 #: src/views/stream/components/RightSettings.vue:50 #: src/views/stream/StreamList.vue:164 +#: src/views/system/Backup/BackupCreator.vue:149 +#: src/views/system/Backup/SystemRestore.vue:94 msgid "OK" msgstr "" @@ -1719,6 +1982,10 @@ msgstr "" msgid "Online" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:24 +msgid "Only zip files are allowed" +msgstr "" + #: src/views/preference/Preference.vue:170 msgid "OpenAI" msgstr "" @@ -1824,6 +2091,14 @@ msgstr "" msgid "Please enter the OTP code:" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:58 +msgid "Please enter the security token" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:153 +msgid "Please enter the security token received during backup" +msgstr "" + #: src/views/certificate/DNSCredential.vue:53 msgid "Please fill in the API authentication credentials provided by your DNS provider." msgstr "" @@ -1876,6 +2151,14 @@ msgstr "" msgid "Please note that the unit of time configurations below are all in seconds." msgstr "" +#: src/views/system/Backup/BackupCreator.vue:107 +msgid "Please save this security token, you will need it for restoration:" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:53 +msgid "Please select a backup file" +msgstr "" + #: src/views/environment/Environment.vue:58 msgid "Please select at least one node to upgrade" msgstr "" @@ -1887,7 +2170,7 @@ msgstr "" msgid "Pre-release" msgstr "" -#: src/routes/index.ts:266 +#: src/routes/modules/preference.ts:10 #: src/views/preference/Preference.vue:141 msgid "Preference" msgstr "" @@ -2142,6 +2425,18 @@ msgstr "" msgid "Restarting" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:81 +msgid "Restore completed successfully" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:165 +msgid "Restore Nginx Configuration" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:176 +msgid "Restore Nginx UI Configuration" +msgstr "" + #: src/views/preference/AuthSettings.vue:107 msgid "RP Display Name" msgstr "" @@ -2184,7 +2479,7 @@ msgstr "" #: src/views/config/ConfigEditor.vue:171 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:41 -#: src/views/site/SiteAdd.vue:46 +#: src/views/site/site_add/SiteAdd.vue:46 msgid "Save error %{msg}" msgstr "" @@ -2231,8 +2526,8 @@ msgstr "" #: src/views/config/ConfigEditor.vue:167 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:39 +#: src/views/site/site_add/SiteAdd.vue:37 #: src/views/site/site_edit/SiteEdit.vue:152 -#: src/views/site/SiteAdd.vue:37 #: src/views/stream/StreamEdit.vue:139 msgid "Saved successfully" msgstr "" @@ -2249,11 +2544,19 @@ msgstr "" msgid "Secret has been copied" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:150 +msgid "Security Token" +msgstr "" + +#: src/views/system/Backup/BackupCreator.vue:94 +msgid "Security Token Information" +msgstr "" + #: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:189 msgid "Selector" msgstr "" -#: src/routes/index.ts:283 +#: src/routes/modules/system.ts:19 #: src/views/system/SelfCheck/SelfCheck.vue:42 msgid "Self Check" msgstr "" @@ -2315,12 +2618,12 @@ msgstr "" msgid "Single Directive" msgstr "" -#: src/routes/index.ts:71 +#: src/routes/modules/sites.ts:34 #: src/views/site/site_category/SiteCategory.vue:10 msgid "Site Categories" msgstr "" -#: src/views/site/SiteAdd.vue:147 +#: src/views/site/site_add/SiteAdd.vue:147 msgid "Site Config Created Successfully" msgstr "" @@ -2328,7 +2631,7 @@ msgstr "" msgid "Site is enabled" msgstr "" -#: src/routes/index.ts:224 +#: src/routes/modules/nginx_log.ts:31 msgid "Site Logs" msgstr "" @@ -2340,7 +2643,7 @@ msgstr "" msgid "Sites Directory" msgstr "" -#: src/routes/index.ts:56 +#: src/routes/modules/sites.ts:19 msgid "Sites List" msgstr "" @@ -2379,6 +2682,10 @@ msgstr "" msgid "Stable" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:187 +msgid "Start Restore" +msgstr "" + #: src/views/certificate/ACMEUser.vue:65 #: src/views/certificate/CertificateList/certColumns.tsx:68 #: src/views/environment/envColumns.tsx:44 @@ -2425,6 +2732,10 @@ msgstr "" msgid "Support communication with the backend through the WebSocket protocol. If your Nginx UI is being used via an Nginx reverse proxy, please refer to this link to write the corresponding configuration file: https://nginxui.com/guide/nginx-proxy-example.html" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:140 +msgid "Supported file type: .zip" +msgstr "" + #: src/views/dashboard/ServerAnalytic.vue:236 #: src/views/dashboard/ServerAnalytic.vue:237 msgid "Swap" @@ -2483,7 +2794,7 @@ msgstr "" msgid "Sync Config Success" msgstr "" -#: src/views/site/site_category/SiteCategory.vue:17 +#: src/views/site/site_category/SiteCategory.vue:18 msgid "Sync Nodes" msgstr "" @@ -2500,19 +2811,27 @@ msgstr "" msgid "Synchronization" msgstr "" -#: src/routes/index.ts:275 +#: src/routes/modules/system.ts:11 msgid "System" msgstr "" +#: src/views/system/Backup/BackupCreator.vue:71 +msgid "System Backup" +msgstr "" + #: src/views/certificate/ACMEUserSelector.vue:88 msgid "System Initial User" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:117 +msgid "System Restore" +msgstr "" + #: src/constants/errors/self_check.ts:2 msgid "Task not found" msgstr "" -#: src/routes/index.ts:194 +#: src/routes/modules/terminal.ts:10 #: src/views/terminal/Terminal.vue:114 msgid "Terminal" msgstr "" @@ -2553,7 +2872,7 @@ msgstr "" msgid "The node name should only contain letters, unicode, numbers, hyphens, dashes, colons, and dots." msgstr "" -#: src/views/site/SiteAdd.vue:120 +#: src/views/site/site_add/SiteAdd.vue:120 msgid "The parameter of server_name is required" msgstr "" @@ -2626,10 +2945,22 @@ msgstr "" msgid "This field should only contain letters, unicode characters, numbers, and -_." msgstr "" +#: src/views/system/Backup/BackupCreator.vue:141 +msgid "This token will only be shown once and cannot be retrieved later. Please make sure to save it in a secure location." +msgstr "" + #: src/constants/form_errors.ts:4 msgid "This value is already taken" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:169 +msgid "This will restore all Nginx configuration files. Nginx will restart after the restoration is complete." +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:180 +msgid "This will restore configuration files and database. Nginx UI will restart after the restoration is complete." +msgstr "" + #: src/views/environment/BatchUpgrader.vue:182 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}." msgstr "" @@ -2717,7 +3048,7 @@ msgstr "" msgid "Updated successfully" msgstr "" -#: src/routes/index.ts:297 +#: src/routes/modules/system.ts:40 #: src/views/environment/Environment.vue:66 #: src/views/system/Upgrade.vue:143 #: src/views/system/Upgrade.vue:226 @@ -2784,6 +3115,10 @@ msgstr "" msgid "Valid" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:159 +msgid "Verify Backup File Integrity" +msgstr "" + #: src/views/environment/envColumns.tsx:31 msgid "Version" msgstr "" @@ -2817,10 +3152,15 @@ msgstr "" #: src/views/config/InspectConfig.vue:33 #: src/views/notification/notificationColumns.tsx:22 #: src/views/preference/components/AddPasskey.vue:82 -#: src/views/site/SiteAdd.vue:115 +#: src/views/site/site_add/SiteAdd.vue:115 +#: src/views/system/Backup/BackupCreator.vue:138 msgid "Warning" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:121 +msgid "Warning: Restore operation will overwrite current configurations. Make sure you have a valid backup file and security token, and carefully select what to restore." +msgstr "" + #: src/views/certificate/DNSCredential.vue:56 msgid "We will add one or more TXT records to the DNS records of your domain for ownership verification." msgstr "" diff --git a/app/src/language/ru_RU/app.po b/app/src/language/ru_RU/app.po index a509faa0..5483b370 100644 --- a/app/src/language/ru_RU/app.po +++ b/app/src/language/ru_RU/app.po @@ -7,8 +7,8 @@ msgstr "" "POT-Creation-Date: \n" "PO-Revision-Date: 2025-03-28 02:45+0300\n" "Last-Translator: Artyom Isrofilov \n" -"Language-Team: Russian \n" +"Language-Team: Russian \n" "Language: ru_RU\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -24,27 +24,29 @@ msgstr "2FA" msgid "2FA Settings" msgstr "Настройки 2FA" -#: src/routes/index.ts:290 +#: src/routes/modules/system.ts:26 msgid "About" msgstr "О проекте" -#: src/routes/index.ts:210 src/views/site/ngx_conf/LogEntry.vue:75 +#: src/routes/modules/nginx_log.ts:17 src/views/site/ngx_conf/LogEntry.vue:75 msgid "Access Logs" msgstr "Журналы доступа" -#: src/routes/index.ts:148 src/views/certificate/ACMEUser.vue:113 +#: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:113 #: src/views/certificate/ACMEUserSelector.vue:85 msgid "ACME User" msgstr "Пользователь ACME" #: src/views/certificate/ACMEUser.vue:95 #: src/views/certificate/CertificateList/certColumns.tsx:97 -#: src/views/certificate/DNSCredential.vue:33 src/views/config/configColumns.tsx:42 +#: src/views/certificate/DNSCredential.vue:33 +#: src/views/config/configColumns.tsx:42 #: src/views/environment/envColumns.tsx:97 #: src/views/notification/notificationColumns.tsx:65 #: src/views/preference/AuthSettings.vue:30 -#: src/views/site/site_category/columns.ts:29 src/views/site/site_list/columns.tsx:76 -#: src/views/stream/StreamList.vue:49 src/views/user/userColumns.tsx:60 +#: src/views/site/site_category/columns.ts:28 +#: src/views/site/site_list/columns.tsx:76 src/views/stream/StreamList.vue:49 +#: src/views/user/userColumns.tsx:60 msgid "Action" msgstr "Действие" @@ -53,7 +55,8 @@ msgstr "Действие" #: src/views/preference/CertSettings.vue:42 #: src/views/site/ngx_conf/config_template/ConfigTemplate.vue:117 #: src/views/site/ngx_conf/NgxServer.vue:162 -#: src/views/site/ngx_conf/NgxUpstream.vue:154 src/views/stream/StreamList.vue:121 +#: src/views/site/ngx_conf/NgxUpstream.vue:154 +#: src/views/stream/StreamList.vue:121 msgid "Add" msgstr "Добавить" @@ -62,7 +65,7 @@ msgstr "Добавить" msgid "Add a passkey" msgstr "Добавить ключ доступа" -#: src/routes/index.ts:118 src/views/config/ConfigEditor.vue:144 +#: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:144 #: src/views/config/ConfigEditor.vue:204 msgid "Add Configuration" msgstr "Добавить конфигурацию" @@ -76,7 +79,7 @@ msgstr "Добавить директиву ниже" msgid "Add Location" msgstr "Добавить Location" -#: src/routes/index.ts:63 src/views/site/SiteAdd.vue:89 +#: src/routes/modules/sites.ts:26 src/views/site/site_add/SiteAdd.vue:89 msgid "Add Site" msgstr "Добавить Сайт" @@ -92,7 +95,8 @@ msgstr "Добавлено успешно" msgid "Additional" msgstr "Дополнительно" -#: src/views/site/site_edit/SiteEdit.vue:205 src/views/stream/StreamEdit.vue:190 +#: src/views/site/site_edit/SiteEdit.vue:205 +#: src/views/stream/StreamEdit.vue:190 msgid "Advance Mode" msgstr "Расширенный режим" @@ -105,7 +109,8 @@ msgstr "Затем, обновите эту страницу и снова на msgid "All" msgstr "Все" -#: src/components/Notification/notifications.ts:121 src/language/constants.ts:58 +#: src/components/Notification/notifications.ts:121 +#: src/language/constants.ts:58 msgid "All Recovery Codes Have Been Used" msgstr "Все коды восстановления были использованы" @@ -179,7 +184,8 @@ msgstr "Вы уверены, что хотите удалить этот эле msgid "Are you sure you want to delete this item?" msgstr "Вы уверены, что хотите удалить этот элемент?" -#: src/views/site/site_list/SiteList.vue:145 src/views/stream/StreamList.vue:165 +#: src/views/site/site_list/SiteList.vue:145 +#: src/views/stream/StreamList.vue:165 msgid "Are you sure you want to delete?" msgstr "Вы уверены, что хотите удалить?" @@ -244,10 +250,15 @@ msgstr "Автообновление отключено для %{name}" msgid "Auto-renewal enabled for %{name}" msgstr "Автообновление включено для %{name}" +#: src/views/system/Backup/SystemRestore.vue:92 +msgid "Automatic Restart" +msgstr "" + #: src/views/certificate/CertificateEditor.vue:255 #: src/views/config/ConfigEditor.vue:213 src/views/config/ConfigList.vue:106 #: src/views/config/ConfigList.vue:180 src/views/nginx_log/NginxLog.vue:173 -#: src/views/site/site_edit/SiteEdit.vue:264 src/views/stream/StreamEdit.vue:246 +#: src/views/site/site_edit/SiteEdit.vue:264 +#: src/views/stream/StreamEdit.vue:246 msgid "Back" msgstr "Назад" @@ -259,6 +270,25 @@ msgstr "Вернуться на главную" msgid "Back to list" msgstr "Возврат к списку" +#: src/routes/modules/system.ts:33 +#, fuzzy +msgid "Backup" +msgstr "Назад" + +#: src/views/system/Backup/SystemRestore.vue:100 +msgid "Backup file integrity check failed, it may have been tampered with" +msgstr "" + +#: src/constants/errors/backup.ts:39 +#, fuzzy +msgid "Backup file not found: {0}" +msgstr "Файл не найден" + +#: src/views/system/Backup/BackupCreator.vue:42 +#, fuzzy +msgid "Backup has been downloaded successfully" +msgstr "Nginx успешно перезагружен" + #: src/views/preference/AuthSettings.vue:129 msgid "Ban Threshold Minutes" msgstr "Порог блокировки в минутах" @@ -271,17 +301,19 @@ msgstr "Заблокированные IP-адреса" msgid "Banned Until" msgstr "Заблокирован до" -#: src/views/site/SiteAdd.vue:95 +#: src/views/site/site_add/SiteAdd.vue:95 msgid "Base information" msgstr "Основная информация" -#: src/views/config/ConfigEditor.vue:241 src/views/preference/Preference.vue:146 +#: src/views/config/ConfigEditor.vue:241 +#: src/views/preference/Preference.vue:146 #: src/views/site/site_edit/RightSettings.vue:79 #: src/views/stream/components/RightSettings.vue:74 msgid "Basic" msgstr "Основные" -#: src/views/site/site_edit/SiteEdit.vue:208 src/views/stream/StreamEdit.vue:193 +#: src/views/site/site_edit/SiteEdit.vue:208 +#: src/views/stream/StreamEdit.vue:193 msgid "Basic Mode" msgstr "Простой режим" @@ -371,17 +403,19 @@ msgstr "Интервал обновления сертификата" msgid "Certificate renewed successfully" msgstr "Сертификат успешно продлен" -#: src/views/certificate/CertificateEditor.vue:128 src/views/site/cert/Cert.vue:33 +#: src/views/certificate/CertificateEditor.vue:128 +#: src/views/site/cert/Cert.vue:33 msgid "Certificate Status" msgid_plural "Certificates Status" msgstr[0] "Статус сертификата" msgstr[1] "Статус сертификатов" -#: src/routes/index.ts:139 src/views/certificate/CertificateList/Certificate.vue:13 +#: src/routes/modules/certificates.ts:11 +#: src/views/certificate/CertificateList/Certificate.vue:13 msgid "Certificates" msgstr "Сертификаты" -#: src/routes/index.ts:156 +#: src/routes/modules/certificates.ts:28 msgid "Certificates List" msgstr "Список сертификатов" @@ -422,14 +456,14 @@ msgstr "" #: src/views/system/SelfCheck/tasks.ts:4 msgid "" -"Check if the sites-available and sites-enabled directories are under the nginx " -"configuration directory." +"Check if the sites-available and sites-enabled directories are under the " +"nginx configuration directory." msgstr "" #: src/views/system/SelfCheck/tasks.ts:8 msgid "" -"Check if the streams-available and streams-enabled directories are under the nginx " -"configuration directory." +"Check if the streams-available and streams-enabled directories are under the " +"nginx configuration directory." msgstr "" #: src/constants/errors/crypto.ts:3 @@ -451,6 +485,10 @@ msgstr "Очистить" msgid "Cleared successfully" msgstr "Очищено успешно" +#: src/views/system/Backup/SystemRestore.vue:137 +msgid "Click or drag backup file to this area to upload" +msgstr "" + #: src/views/preference/components/TOTP.vue:110 msgid "Click to copy" msgstr "" @@ -466,6 +504,11 @@ msgstr "Команда" msgid "Comments" msgstr "Комментарии" +#: src/constants/errors/backup.ts:13 +#, fuzzy +msgid "Config path is empty" +msgstr "Шаблоны конфигурации" + #: src/views/site/ngx_conf/config_template/ConfigTemplate.vue:84 msgid "Config Templates" msgstr "Шаблоны конфигурации" @@ -474,7 +517,7 @@ msgstr "Шаблоны конфигурации" msgid "Configuration file is test successful" msgstr "Проверка конфигурации успешна" -#: src/views/site/SiteAdd.vue:101 +#: src/views/site/site_add/SiteAdd.vue:101 msgid "Configuration Name" msgstr "Название конфигурации" @@ -482,7 +525,7 @@ msgstr "Название конфигурации" msgid "Configurations" msgstr "Конфигурации" -#: src/views/site/SiteAdd.vue:96 +#: src/views/site/site_add/SiteAdd.vue:96 msgid "Configure SSL" msgstr "Настроить SSL" @@ -506,7 +549,13 @@ msgstr "Содержание" msgid "Copied" msgstr "Скопировано" +#: src/views/system/Backup/BackupCreator.vue:128 +#, fuzzy +msgid "Copied!" +msgstr "Скопировано" + #: src/components/SensitiveString/SensitiveString.vue:37 +#: src/views/system/Backup/BackupCreator.vue:128 msgid "Copy" msgstr "Копировать" @@ -530,10 +579,15 @@ msgstr "CPU:" msgid "Create" msgstr "Создать" -#: src/views/site/SiteAdd.vue:157 +#: src/views/site/site_add/SiteAdd.vue:157 msgid "Create Another" msgstr "Создать еще" +#: src/views/system/Backup/BackupCreator.vue:86 +#, fuzzy +msgid "Create Backup" +msgstr "Создан в" + #: src/views/config/ConfigList.vue:116 msgid "Create File" msgstr "Создать файл" @@ -542,9 +596,15 @@ msgstr "Создать файл" msgid "Create Folder" msgstr "Создать папку" +#: src/views/system/Backup/BackupCreator.vue:75 +msgid "" +"Create system backups including Nginx configuration and Nginx UI settings. " +"Backup files will be automatically downloaded to your computer." +msgstr "" + #: src/views/notification/notificationColumns.tsx:58 #: src/views/preference/components/Passkey.vue:95 -#: src/views/site/site_category/columns.ts:15 src/views/user/userColumns.tsx:48 +#: src/views/site/site_category/columns.ts:16 src/views/user/userColumns.tsx:48 msgid "Created at" msgstr "Создан в" @@ -584,10 +644,11 @@ msgstr "Пользовательский" #: src/views/preference/BasicSettings.vue:34 #, fuzzy msgid "" -"Customize the name of local node to be displayed in the environment indicator." +"Customize the name of local node to be displayed in the environment " +"indicator." msgstr "Настройте имя локального сервера для отображения в индикаторе среды." -#: src/routes/index.ts:38 src/views/config/ConfigEditor.vue:134 +#: src/routes/modules/dashboard.ts:10 src/views/config/ConfigEditor.vue:134 #: src/views/config/ConfigEditor.vue:97 src/views/config/ConfigList.vue:64 msgid "Dashboard" msgstr "Доска" @@ -608,7 +669,8 @@ msgstr "Ошибка расшифровки" #: src/components/StdDesign/StdDataDisplay/StdTable.vue:519 #: src/views/site/ngx_conf/NgxServer.vue:110 #: src/views/site/ngx_conf/NgxUpstream.vue:128 -#: src/views/site/site_list/SiteList.vue:154 src/views/stream/StreamList.vue:174 +#: src/views/site/site_list/SiteList.vue:154 +#: src/views/stream/StreamList.vue:174 msgid "Delete" msgstr "Удалить" @@ -708,7 +770,8 @@ msgstr "" msgid "Directives" msgstr "Директивы" -#: src/views/site/site_list/SiteList.vue:125 src/views/stream/StreamList.vue:145 +#: src/views/site/site_list/SiteList.vue:125 +#: src/views/stream/StreamList.vue:145 msgid "Disable" msgstr "Отключить" @@ -756,8 +819,10 @@ msgstr "Включение %{conf_name} in %{node_name} нипалучилася msgid "Disable stream %{name} from %{node} successfully" msgstr "Включение %{conf_name} in %{node_name} успешно" -#: src/views/environment/envColumns.tsx:61 src/views/environment/envColumns.tsx:79 -#: src/views/site/site_edit/SiteEdit.vue:190 src/views/site/site_list/columns.tsx:53 +#: src/views/environment/envColumns.tsx:61 +#: src/views/environment/envColumns.tsx:79 +#: src/views/site/site_edit/SiteEdit.vue:190 +#: src/views/site/site_list/columns.tsx:53 #: src/views/site/site_list/columns.tsx:62 src/views/stream/StreamEdit.vue:176 #: src/views/stream/StreamList.vue:33 src/views/user/userColumns.tsx:41 msgid "Disabled" @@ -774,7 +839,8 @@ msgstr "Отключено успешно" msgid "Disk IO" msgstr "Нагрузка на Диск IO" -#: src/routes/index.ts:184 src/views/certificate/DNSCredential.vue:40 +#: src/routes/modules/certificates.ts:56 +#: src/views/certificate/DNSCredential.vue:40 msgid "DNS Credentials" msgstr "DNS учетные данные" @@ -838,7 +904,8 @@ msgstr "Домен" #: src/views/certificate/CertificateEditor.vue:112 msgid "Domains list is empty, try to reopen Auto Cert for %{config}" -msgstr "Список доменов пуст, попробуйте заново создать авто-сертификат для %{config}" +msgstr "" +"Список доменов пуст, попробуйте заново создать авто-сертификат для %{config}" #: src/language/constants.ts:27 msgid "Download latest release error" @@ -854,12 +921,12 @@ msgstr "Включен пробный режим" #: src/views/preference/components/AddPasskey.vue:101 msgid "" -"Due to the security policies of some browsers, you cannot use passkeys on non-" -"HTTPS websites, except when running on localhost." +"Due to the security policies of some browsers, you cannot use passkeys on " +"non-HTTPS websites, except when running on localhost." msgstr "" -"Из-за политик безопасности некоторых браузеров, вы не можете использовать ключи " -"доступа на сайтах без HTTPS, за исключением случаев, когда они запускаются на " -"localhost." +"Из-за политик безопасности некоторых браузеров, вы не можете использовать " +"ключи доступа на сайтах без HTTPS, за исключением случаев, когда они " +"запускаются на localhost." #: src/views/site/site_list/SiteDuplicate.vue:72 #: src/views/site/site_list/SiteList.vue:140 @@ -878,19 +945,20 @@ msgstr "Успешно дублировано на локальный" msgid "Edit" msgstr "Редактировать %{n}" -#: src/views/site/site_edit/SiteEdit.vue:179 src/views/stream/StreamEdit.vue:165 +#: src/views/site/site_edit/SiteEdit.vue:179 +#: src/views/stream/StreamEdit.vue:165 msgid "Edit %{n}" msgstr "Редактировать %{n}" -#: src/routes/index.ts:128 src/views/config/ConfigEditor.vue:204 +#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:204 msgid "Edit Configuration" msgstr "Редактировать Конфигурацию" -#: src/routes/index.ts:78 +#: src/routes/modules/sites.ts:41 msgid "Edit Site" msgstr "Редактировать Сайт" -#: src/routes/index.ts:98 +#: src/routes/modules/streams.ts:19 msgid "Edit Stream" msgstr "Редактировать поток" @@ -902,7 +970,8 @@ msgstr "Электронная почта" msgid "Email (*)" msgstr "Email (*)" -#: src/views/site/site_list/SiteList.vue:133 src/views/stream/StreamList.vue:153 +#: src/views/site/site_list/SiteList.vue:133 +#: src/views/stream/StreamList.vue:153 msgid "Enable" msgstr "Включить" @@ -914,7 +983,7 @@ msgstr "Двухфакторная аутентификация успешно msgid "Enable auto-renewal failed for %{name}" msgstr "Не удалось включить автоматическое продление для %{name}" -#: src/views/site/SiteAdd.vue:43 +#: src/views/site/site_add/SiteAdd.vue:43 msgid "Enable failed" msgstr "Не удалось включить" @@ -964,10 +1033,12 @@ msgstr "Включить TLS" msgid "Enable TOTP" msgstr "Включить TOTP" -#: src/views/environment/envColumns.tsx:70 src/views/environment/envColumns.tsx:76 +#: src/views/environment/envColumns.tsx:70 +#: src/views/environment/envColumns.tsx:76 #: src/views/preference/LogrotateSettings.vue:19 #: src/views/site/site_edit/RightSettings.vue:82 -#: src/views/site/site_edit/SiteEdit.vue:184 src/views/site/site_list/columns.tsx:49 +#: src/views/site/site_edit/SiteEdit.vue:184 +#: src/views/site/site_list/columns.tsx:49 #: src/views/site/site_list/columns.tsx:61 #: src/views/stream/components/RightSettings.vue:76 #: src/views/stream/StreamEdit.vue:170 src/views/stream/StreamList.vue:29 @@ -975,8 +1046,9 @@ msgstr "Включить TOTP" msgid "Enabled" msgstr "Включено" +#: src/views/site/site_add/SiteAdd.vue:40 #: src/views/site/site_edit/RightSettings.vue:33 -#: src/views/site/site_list/SiteList.vue:46 src/views/site/SiteAdd.vue:40 +#: src/views/site/site_list/SiteList.vue:46 #: src/views/stream/components/RightSettings.vue:29 #: src/views/stream/StreamList.vue:61 msgid "Enabled successfully" @@ -990,7 +1062,8 @@ msgstr "Использовать для сайта Let's Encrypt" msgid "Environment variables cleaned" msgstr "Переменные окружения очищены" -#: src/routes/index.ts:234 src/views/dashboard/Environments.vue:83 +#: src/routes/modules/environments.ts:11 +#: src/views/dashboard/Environments.vue:83 #: src/views/environment/Environment.vue:43 msgid "Environments" msgstr "Окружения" @@ -1000,7 +1073,7 @@ msgstr "Окружения" msgid "Error" msgstr "Ошибка" -#: src/routes/index.ts:217 src/views/site/ngx_conf/LogEntry.vue:83 +#: src/routes/modules/nginx_log.ts:24 src/views/site/ngx_conf/LogEntry.vue:83 msgid "Error Logs" msgstr "Ошибка логирования" @@ -1025,11 +1098,130 @@ msgstr "Экспорт" msgid "Fail to obtain certificate" msgstr "Не удалось получить сертификат" +#: src/constants/errors/backup.ts:5 +msgid "Failed to backup Nginx config files: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:4 +msgid "Failed to backup Nginx UI files: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:17 +#, fuzzy +msgid "Failed to calculate hash: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:53 +msgid "Failed to calculate Nginx hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:52 +msgid "Failed to calculate Nginx UI hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:14 +msgid "Failed to copy config file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:15 +msgid "Failed to copy database directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:16 +#, fuzzy +msgid "Failed to copy database file: {0}" +msgstr "Не удалось отключить %{msg}" + +#: src/constants/errors/backup.ts:30 +msgid "Failed to copy file content: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:19 +msgid "Failed to copy Nginx config directory: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:9 #, fuzzy msgid "Failed to create backup" msgstr "Не удалось включить %{msg}" +#: src/constants/errors/backup.ts:12 +#, fuzzy +msgid "Failed to create backup file: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:44 +#, fuzzy +msgid "Failed to create directory: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:46 +#, fuzzy +msgid "Failed to create file: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:6 +#, fuzzy +msgid "Failed to create hash info file: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:45 +#, fuzzy +msgid "Failed to create parent directory: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:32 +msgid "Failed to create restore directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:2 +#, fuzzy +msgid "Failed to create temporary directory" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:3 +#, fuzzy +msgid "Failed to create temporary subdirectory" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:9 +#, fuzzy +msgid "Failed to create zip archive: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:27 +#, fuzzy +msgid "Failed to create zip entry: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:26 +#, fuzzy +msgid "Failed to create zip file: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:29 +#, fuzzy +msgid "Failed to create zip header: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:24 +#, fuzzy +msgid "Failed to decrypt data: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:49 +#, fuzzy +msgid "Failed to decrypt file: {0}" +msgstr "Не удалось отключить %{msg}" + +#: src/constants/errors/backup.ts:35 +msgid "Failed to decrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:34 +msgid "Failed to decrypt Nginx UI directory: {0}" +msgstr "" + #: src/views/site/site_edit/RightSettings.vue:45 #: src/views/site/site_list/SiteList.vue:60 #: src/views/stream/components/RightSettings.vue:41 @@ -1044,22 +1236,109 @@ msgstr "Не удалось отключить %{msg}" msgid "Failed to enable %{msg}" msgstr "Не удалось включить %{msg}" +#: src/constants/errors/backup.ts:23 +#, fuzzy +msgid "Failed to encrypt data: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:21 +#, fuzzy +msgid "Failed to encrypt file: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:8 +msgid "Failed to encrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:7 +msgid "Failed to encrypt Nginx UI directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:33 +#, fuzzy +msgid "Failed to extract archive: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:10 +#, fuzzy +msgid "Failed to generate AES key: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:11 +#, fuzzy +msgid "Failed to generate initialization vector: {0}" +msgstr "Не удалось получить информацию о сертификате" + #: src/language/constants.ts:5 msgid "Failed to get certificate information" msgstr "Не удалось получить информацию о сертификате" +#: src/constants/errors/backup.ts:28 +#, fuzzy +msgid "Failed to open source file: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:47 +#, fuzzy +msgid "Failed to open zip entry: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:43 +#, fuzzy +msgid "Failed to open zip file: {0}" +msgstr "Не удалось включить %{msg}" + #: src/constants/errors/self_check.ts:4 msgid "Failed to parse nginx.conf" msgstr "" +#: src/constants/errors/backup.ts:48 +msgid "Failed to read encrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:20 +#, fuzzy +msgid "Failed to read file: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:51 +msgid "Failed to read hash info file: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:3 msgid "Failed to read nginx.conf" msgstr "" -#: src/views/site/site_edit/SiteEdit.vue:135 src/views/stream/StreamEdit.vue:122 +#: src/constants/errors/backup.ts:37 +msgid "Failed to restore Nginx configs: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:38 +msgid "Failed to restore Nginx UI files: {0}" +msgstr "" + +#: src/views/site/site_edit/SiteEdit.vue:135 +#: src/views/stream/StreamEdit.vue:122 msgid "Failed to save, syntax error(s) was detected in the configuration." msgstr "Не удалось сохранить, обнаружены синтаксические ошибки в конфигурации." +#: src/constants/errors/backup.ts:36 +#, fuzzy +msgid "Failed to verify hashes: {0}" +msgstr "Не удалось включить %{msg}" + +#: src/constants/errors/backup.ts:50 +msgid "Failed to write decrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:22 +msgid "Failed to write encrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:31 +msgid "Failed to write to zip buffer: {0}" +msgstr "" + #: src/language/constants.ts:32 msgid "File exists" msgstr "Файл существует" @@ -1076,7 +1355,7 @@ msgstr "" msgid "Filter" msgstr "Фильтр" -#: src/language/constants.ts:19 src/views/site/SiteAdd.vue:97 +#: src/language/constants.ts:19 src/views/site/site_add/SiteAdd.vue:97 msgid "Finished" msgstr "Готово" @@ -1086,10 +1365,11 @@ msgstr "" #: src/views/preference/components/AddPasskey.vue:71 msgid "" -"Follow the instructions in the dialog to complete the passkey registration process." +"Follow the instructions in the dialog to complete the passkey registration " +"process." msgstr "" -"Следуйте инструкциям в всплывающем окне, чтобы завершить процесс регистрации ключа " -"доступа." +"Следуйте инструкциям в всплывающем окне, чтобы завершить процесс регистрации " +"ключа доступа." #: src/views/preference/BasicSettings.vue:59 #: src/views/preference/BasicSettings.vue:71 @@ -1152,11 +1432,15 @@ msgstr "Получение сертификата, пожалуйста, под msgid "Github Proxy" msgstr "Прокси Github" +#: src/constants/errors/backup.ts:54 +msgid "Hash verification failed: file integrity compromised" +msgstr "" + #: src/components/SensitiveString/SensitiveString.vue:40 msgid "Hide" msgstr "Скрыть" -#: src/routes/index.ts:30 +#: src/routes/index.ts:47 msgid "Home" msgstr "Главная" @@ -1186,35 +1470,37 @@ msgstr "Если оставить пустым, будет использова #: src/views/preference/AuthSettings.vue:145 msgid "" -"If the number of login failed attempts from a ip reach the max attempts in ban " -"threshold minutes, the ip will be banned for a period of time." +"If the number of login failed attempts from a ip reach the max attempts in " +"ban threshold minutes, the ip will be banned for a period of time." msgstr "" -"Если количество неудачных попыток входа с IP достигнет максимального количества " -"попыток в течение пороговых минут блокировки, IP будет заблокирован на " -"определенный период времени." +"Если количество неудачных попыток входа с IP достигнет максимального " +"количества попыток в течение пороговых минут блокировки, IP будет " +"заблокирован на определенный период времени." #: src/views/preference/components/AddPasskey.vue:70 msgid "If your browser supports WebAuthn Passkey, a dialog box will appear." -msgstr "Если ваш браузер поддерживает WebAuthn Passkey, появится диалоговое окно." +msgstr "" +"Если ваш браузер поддерживает WebAuthn Passkey, появится диалоговое окно." #: src/views/site/cert/components/AutoCertStepOne.vue:108 msgid "" -"If your domain has CNAME records and you cannot obtain certificates, you need to " -"enable this option." +"If your domain has CNAME records and you cannot obtain certificates, you " +"need to enable this option." msgstr "" -"Если у вашего домена есть записи CNAME и вы не можете получить сертификаты, вам " -"нужно включить эту опцию." +"Если у вашего домена есть записи CNAME и вы не можете получить сертификаты, " +"вам нужно включить эту опцию." #: src/views/certificate/CertificateList/Certificate.vue:20 msgid "Import" msgstr "Импорт" -#: src/routes/index.ts:174 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:46 +#: src/views/certificate/CertificateEditor.vue:85 msgid "Import Certificate" msgstr "Импортировать сертификат" -#: src/components/StdDesign/StdDetail/StdDetail.vue:81 src/constants/index.ts:18 -#: src/views/notification/notificationColumns.tsx:29 +#: src/components/StdDesign/StdDetail/StdDetail.vue:81 +#: src/constants/index.ts:18 src/views/notification/notificationColumns.tsx:29 msgid "Info" msgstr "Информация" @@ -1234,7 +1520,7 @@ msgstr "Введите код из приложения:" msgid "Input the recovery code:" msgstr "Введите код восстановления:" -#: src/routes/index.ts:312 src/views/other/Install.vue:134 +#: src/routes/modules/auth.ts:8 src/views/other/Install.vue:134 msgid "Install" msgstr "Установить" @@ -1250,7 +1536,21 @@ msgstr "Интервал" msgid "Invalid" msgstr "Недействительно" -#: src/views/config/components/Rename.vue:64 src/views/config/ConfigEditor.vue:250 +#: src/constants/errors/backup.ts:42 +msgid "Invalid AES IV format: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:41 +msgid "Invalid AES key format: {0}" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:67 +#, fuzzy +msgid "Invalid file object" +msgstr "Неверное имя файла" + +#: src/views/config/components/Rename.vue:64 +#: src/views/config/ConfigEditor.vue:250 msgid "Invalid filename" msgstr "Неверное имя файла" @@ -1262,6 +1562,10 @@ msgstr "Недопустимое имя папки" msgid "Invalid otp code" msgstr "Неверный код OTP" +#: src/constants/errors/backup.ts:25 +msgid "Invalid padding in decrypted data" +msgstr "" + #: src/components/TwoFA/use2FAModal.ts:61 msgid "Invalid passcode or recovery code" msgstr "Неверный пароль или код восстановления" @@ -1274,6 +1578,11 @@ msgstr "Неверный код восстановления" msgid "Invalid request format" msgstr "" +#: src/constants/errors/backup.ts:40 +#, fuzzy +msgid "Invalid security token format" +msgstr "Неверный код восстановления" + #: src/views/preference/AuthSettings.vue:18 msgid "IP" msgstr "IP" @@ -1300,8 +1609,8 @@ msgstr "Jwt секрет" #: src/views/preference/components/RecoveryCodes.vue:74 msgid "" -"Keep your recovery codes as safe as your password. We recommend saving them with a " -"password manager." +"Keep your recovery codes as safe as your password. We recommend saving them " +"with a password manager." msgstr "" #: src/views/certificate/CertificateList/certColumns.tsx:62 @@ -1352,7 +1661,8 @@ msgstr "Lego отключает поддержку CNAME" msgid "License" msgstr "Лицензия" -#: src/views/dashboard/Environments.vue:141 src/views/dashboard/Environments.vue:156 +#: src/views/dashboard/Environments.vue:141 +#: src/views/dashboard/Environments.vue:156 msgid "Link Start" msgstr "Начало ссылки" @@ -1389,7 +1699,7 @@ msgstr "Локации" msgid "Log" msgstr "Журнал" -#: src/routes/index.ts:318 src/views/other/Login.vue:222 +#: src/routes/modules/auth.ts:14 src/views/other/Login.vue:222 msgid "Login" msgstr "Логин" @@ -1407,18 +1717,19 @@ msgstr "Прокрутка" #: src/views/preference/LogrotateSettings.vue:12 msgid "" -"Logrotate, by default, is enabled in most mainstream Linux distributions for users " -"who install Nginx UI on the host machine, so you don't need to modify the " -"parameters on this page. For users who install Nginx UI using Docker containers, " -"you can manually enable this option. The crontab task scheduler of Nginx UI will " -"execute the logrotate command at the interval you set in minutes." +"Logrotate, by default, is enabled in most mainstream Linux distributions for " +"users who install Nginx UI on the host machine, so you don't need to modify " +"the parameters on this page. For users who install Nginx UI using Docker " +"containers, you can manually enable this option. The crontab task scheduler " +"of Nginx UI will execute the logrotate command at the interval you set in " +"minutes." msgstr "" -"Logrotate по умолчанию включен в большинстве основных дистрибутивов Linux для " -"пользователей, которые устанавливают Nginx UI на хост-машину, поэтому вам не нужно " -"изменять параметры на этой странице. Для пользователей, которые устанавливают " -"Nginx UI с использованием Docker-контейнеров, вы можете вручную включить эту " -"опцию. Планировщик задач crontab Nginx UI будет выполнять команду logrotate с " -"интервалом, который вы установите в минутах." +"Logrotate по умолчанию включен в большинстве основных дистрибутивов Linux " +"для пользователей, которые устанавливают Nginx UI на хост-машину, поэтому " +"вам не нужно изменять параметры на этой странице. Для пользователей, которые " +"устанавливают Nginx UI с использованием Docker-контейнеров, вы можете " +"вручную включить эту опцию. Планировщик задач crontab Nginx UI будет " +"выполнять команду logrotate с интервалом, который вы установите в минутах." #: src/views/site/cert/components/AutoCertStepOne.vue:53 msgid "" @@ -1428,20 +1739,20 @@ msgstr "" "Убедитесь, что вы настроили обратный прокси для каталога .well-known на " "HTTPChallengePort перед получением сертификата." -#: src/routes/index.ts:108 src/views/config/ConfigEditor.vue:102 +#: src/routes/modules/config.ts:10 src/views/config/ConfigEditor.vue:102 #: src/views/config/ConfigEditor.vue:139 src/views/config/ConfigList.vue:69 msgid "Manage Configs" msgstr "Конфигурации" -#: src/routes/index.ts:47 src/views/site/site_list/SiteList.vue:94 +#: src/routes/modules/sites.ts:10 src/views/site/site_list/SiteList.vue:94 msgid "Manage Sites" msgstr "Сайты" -#: src/routes/index.ts:89 src/views/stream/StreamList.vue:119 +#: src/routes/modules/streams.ts:10 src/views/stream/StreamList.vue:119 msgid "Manage Streams" msgstr "Управление потоками" -#: src/routes/index.ts:257 src/views/user/User.vue:10 +#: src/routes/modules/user.ts:10 src/views/user/User.vue:10 msgid "Manage Users" msgstr "Пользователи" @@ -1477,11 +1788,12 @@ msgstr "Модель" msgid "Modify" msgstr "Изменить" -#: src/routes/index.ts:164 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:36 +#: src/views/certificate/CertificateEditor.vue:85 msgid "Modify Certificate" msgstr "Изменить сертификат" -#: src/views/site/SiteAdd.vue:154 +#: src/views/site/site_add/SiteAdd.vue:154 msgid "Modify Config" msgstr "Изменить конфигурацию" @@ -1497,8 +1809,9 @@ msgstr "Многострочная директива" #: src/views/certificate/CertificateEditor.vue:160 #: src/views/certificate/CertificateList/certColumns.tsx:10 #: src/views/certificate/DNSCredential.vue:11 -#: src/views/config/components/Mkdir.vue:64 src/views/config/configColumns.tsx:7 -#: src/views/config/ConfigEditor.vue:256 src/views/environment/envColumns.tsx:9 +#: src/views/config/components/Mkdir.vue:64 +#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:256 +#: src/views/environment/envColumns.tsx:9 #: src/views/preference/components/AddPasskey.vue:75 #: src/views/site/ngx_conf/NgxUpstream.vue:177 #: src/views/site/site_category/columns.ts:7 @@ -1540,7 +1853,8 @@ msgid "New version released" msgstr "Вышла новая версия" #: src/views/certificate/WildcardCertificate.vue:91 -#: src/views/site/cert/components/ObtainCert.vue:211 src/views/site/SiteAdd.vue:141 +#: src/views/site/cert/components/ObtainCert.vue:211 +#: src/views/site/site_add/SiteAdd.vue:141 msgid "Next" msgstr "Дальше" @@ -1576,7 +1890,18 @@ msgstr "" msgid "Nginx conf not include stream-enabled" msgstr "" -#: src/views/site/site_edit/SiteEdit.vue:223 src/views/stream/StreamEdit.vue:208 +#: src/constants/errors/backup.ts:18 +#, fuzzy +msgid "Nginx config directory is not set" +msgstr "Белый список директорий для логов Nginx" + +#: src/views/system/Backup/SystemRestore.vue:84 +#, fuzzy +msgid "Nginx configuration has been restored" +msgstr "Ошибка разбора конфигурации Nginx" + +#: src/views/site/site_edit/SiteEdit.vue:223 +#: src/views/stream/StreamEdit.vue:208 msgid "Nginx Configuration Parse Error" msgstr "Ошибка разбора конфигурации Nginx" @@ -1597,7 +1922,7 @@ msgstr "Путь для Nginx Error Log" msgid "Nginx is not running" msgstr "Nginx не работает" -#: src/routes/index.ts:202 src/views/nginx_log/NginxLog.vue:148 +#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:148 msgid "Nginx Log" msgstr "Журнал" @@ -1627,6 +1952,18 @@ msgstr "Терминальная команда запуска" msgid "Nginx restarted successfully" msgstr "Nginx успешно перезапущен" +#: src/views/system/Backup/SystemRestore.vue:88 +#, fuzzy +msgid "Nginx UI configuration has been restored" +msgstr "Ошибка разбора конфигурации Nginx" + +#: src/views/system/Backup/SystemRestore.vue:93 +#, fuzzy +msgid "" +"Nginx UI configuration has been restored and will restart automatically in a " +"few seconds." +msgstr "Ошибка разбора конфигурации Nginx" + #: src/components/ChatGPT/ChatGPT.vue:374 #: src/components/Notification/Notification.vue:133 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:63 @@ -1635,10 +1972,12 @@ msgstr "Nginx успешно перезапущен" #: src/components/StdDesign/StdDataDisplay/StdTable.vue:524 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:538 #: src/views/notification/Notification.vue:37 -#: src/views/preference/AuthSettings.vue:164 src/views/preference/CertSettings.vue:70 +#: src/views/preference/AuthSettings.vue:164 +#: src/views/preference/CertSettings.vue:70 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:97 #: src/views/site/ngx_conf/LocationEditor.vue:88 -#: src/views/site/site_list/SiteList.vue:143 src/views/stream/StreamList.vue:163 +#: src/views/site/site_list/SiteList.vue:143 +#: src/views/stream/StreamList.vue:163 msgid "No" msgstr "Нет" @@ -1654,7 +1993,7 @@ msgstr "Секрет узла" msgid "Not After" msgstr "Не позднее" -#: src/routes/index.ts:324 +#: src/routes/modules/error.ts:8 msgid "Not Found" msgstr "Не найден" @@ -1669,17 +2008,18 @@ msgstr "Заметка" #: src/views/site/site_edit/RightSettings.vue:120 msgid "" -"Note, if the configuration file include other configurations or certificates, " -"please synchronize them to the remote nodes in advance." +"Note, if the configuration file include other configurations or " +"certificates, please synchronize them to the remote nodes in advance." msgstr "" -"Примечание: если файл конфигурации включает другие настройки или сертификаты, " -"пожалуйста, заранее синхронизируйте их с удалёнными узлами." +"Примечание: если файл конфигурации включает другие настройки или " +"сертификаты, пожалуйста, заранее синхронизируйте их с удалёнными узлами." #: src/views/notification/Notification.vue:28 msgid "Notification" msgstr "Уведомление" -#: src/components/Notification/Notification.vue:131 src/routes/index.ts:248 +#: src/components/Notification/Notification.vue:131 +#: src/routes/modules/notifications.ts:10 msgid "Notifications" msgstr "Уведомления" @@ -1697,13 +2037,15 @@ msgstr "OCSP Must Staple" #: src/views/site/cert/components/AutoCertStepOne.vue:99 msgid "" -"OCSP Must Staple may cause errors for some users on first access using Firefox." +"OCSP Must Staple may cause errors for some users on first access using " +"Firefox." msgstr "" -"OCSP Must Staple может вызвать ошибки у некоторых пользователей при первом доступе " -"через Firefox." +"OCSP Must Staple может вызвать ошибки у некоторых пользователей при первом " +"доступе через Firefox." #: src/components/NodeSelector/NodeSelector.vue:109 -#: src/views/dashboard/Environments.vue:107 src/views/environment/envColumns.tsx:56 +#: src/views/dashboard/Environments.vue:107 +#: src/views/environment/envColumns.tsx:56 msgid "Offline" msgstr "Оффлайн" @@ -1727,6 +2069,8 @@ msgstr "Ок" #: src/views/site/site_list/SiteList.vue:144 #: src/views/stream/components/RightSettings.vue:50 #: src/views/stream/StreamList.vue:164 +#: src/views/system/Backup/BackupCreator.vue:149 +#: src/views/system/Backup/SystemRestore.vue:94 msgid "OK" msgstr "ОК" @@ -1736,10 +2080,15 @@ msgstr "После завершения проверки записи будут #: src/components/NodeSelector/NodeSelector.vue:103 #: src/components/NodeSelector/NodeSelector.vue:89 -#: src/views/dashboard/Environments.vue:100 src/views/environment/envColumns.tsx:52 +#: src/views/dashboard/Environments.vue:100 +#: src/views/environment/envColumns.tsx:52 msgid "Online" msgstr "Онлайн" +#: src/views/system/Backup/SystemRestore.vue:24 +msgid "Only zip files are allowed" +msgstr "" + #: src/views/preference/Preference.vue:170 msgid "OpenAI" msgstr "OpenAI" @@ -1786,9 +2135,9 @@ msgstr "" #: src/views/preference/components/Passkey.vue:62 msgid "" -"Passkeys are webauthn credentials that validate your identity using touch, facial " -"recognition, a device password, or a PIN. They can be used as a password " -"replacement or as a 2FA method." +"Passkeys are webauthn credentials that validate your identity using touch, " +"facial recognition, a device password, or a PIN. They can be used as a " +"password replacement or as a 2FA method." msgstr "" #: src/views/other/Login.vue:183 src/views/user/userColumns.tsx:18 @@ -1840,8 +2189,8 @@ msgstr "" #: src/views/preference/components/AddPasskey.vue:69 msgid "" -"Please enter a name for the passkey you wish to create and click the OK button " -"below." +"Please enter a name for the passkey you wish to create and click the OK " +"button below." msgstr "" #: src/components/TwoFA/Authorization.vue:85 @@ -1849,11 +2198,22 @@ msgstr "" msgid "Please enter the OTP code:" msgstr "Пожалуйста, введите код 2FA:" +#: src/views/system/Backup/SystemRestore.vue:58 +#, fuzzy +msgid "Please enter the security token" +msgstr "Пожалуйста, введите код 2FA:" + +#: src/views/system/Backup/SystemRestore.vue:153 +msgid "Please enter the security token received during backup" +msgstr "" + #: src/views/certificate/DNSCredential.vue:53 msgid "" -"Please fill in the API authentication credentials provided by your DNS provider." +"Please fill in the API authentication credentials provided by your DNS " +"provider." msgstr "" -"Пожалуйста, заполните учетные данные API, предоставленные вашим DNS-провайдером." +"Пожалуйста, заполните учетные данные API, предоставленные вашим DNS-" +"провайдером." #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:106 msgid "Please fill in the required fields" @@ -1861,19 +2221,22 @@ msgstr "Пожалуйста, заполните обязательные пол #: src/views/site/cert/components/AutoCertStepOne.vue:57 msgid "" -"Please first add credentials in Certification > DNS Credentials, and then select " -"one of the credentialsbelow to request the API of the DNS provider." +"Please first add credentials in Certification > DNS Credentials, and then " +"select one of the credentialsbelow to request the API of the DNS provider." msgstr "" -"Пожалуйста, сначала добавьте учетные данные в Certification > DNS Credentials, а " -"затем выберите одну из учетных данных ниже, чтобы запросить API провайдера DNS." +"Пожалуйста, сначала добавьте учетные данные в Certification > DNS " +"Credentials, а затем выберите одну из учетных данных ниже, чтобы запросить " +"API провайдера DNS." -#: src/components/Notification/notifications.ts:122 src/language/constants.ts:59 +#: src/components/Notification/notifications.ts:122 +#: src/language/constants.ts:59 msgid "" "Please generate new recovery codes in the preferences immediately to prevent " "lockout." msgstr "" -#: src/views/config/components/Rename.vue:63 src/views/config/ConfigEditor.vue:249 +#: src/views/config/components/Rename.vue:63 +#: src/views/config/ConfigEditor.vue:249 msgid "Please input a filename" msgstr "Пожалуйста, введите имя файла" @@ -1883,15 +2246,19 @@ msgstr "Пожалуйста, введите имя папки" #: src/views/stream/components/StreamDuplicate.vue:25 msgid "" -"Please input name, this will be used as the filename of the new configuration!" +"Please input name, this will be used as the filename of the new " +"configuration!" msgstr "" -"Введите имя, оно будет использоваться в качестве имени файла нового поздравляем!" +"Введите имя, оно будет использоваться в качестве имени файла нового " +"поздравляем!" #: src/views/site/site_list/SiteDuplicate.vue:33 msgid "" -"Please input name, this will be used as the filename of the new configuration." +"Please input name, this will be used as the filename of the new " +"configuration." msgstr "" -"Введите имя, оно будет использоваться в качестве имени файла новой конфигурации." +"Введите имя, оно будет использоваться в качестве имени файла новой " +"конфигурации." #: src/views/other/Install.vue:32 msgid "Please input your E-mail!" @@ -1906,10 +2273,20 @@ msgid "Please input your username!" msgstr "Введите ваше имя пользователя!" #: src/views/certificate/DNSCredential.vue:62 -msgid "Please note that the unit of time configurations below are all in seconds." +msgid "" +"Please note that the unit of time configurations below are all in seconds." msgstr "" -"Обратите внимание, что единица измерения времени в конфигурациях ниже указана в " -"секундах." +"Обратите внимание, что единица измерения времени в конфигурациях ниже " +"указана в секундах." + +#: src/views/system/Backup/BackupCreator.vue:107 +msgid "Please save this security token, you will need it for restoration:" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:53 +#, fuzzy +msgid "Please select a backup file" +msgstr "Пожалуйста, выберите хотя бы один узел!" #: src/views/environment/Environment.vue:58 msgid "Please select at least one node to upgrade" @@ -1921,7 +2298,7 @@ msgstr "Пожалуйста, выберите хотя бы один узел" msgid "Pre-release" msgstr "Предварительный выпуск" -#: src/routes/index.ts:266 src/views/preference/Preference.vue:141 +#: src/routes/modules/preference.ts:10 src/views/preference/Preference.vue:141 msgid "Preference" msgstr "Настройки" @@ -1987,11 +2364,11 @@ msgstr "Код восстановления" #: src/views/preference/components/RecoveryCodes.vue:73 msgid "" -"Recovery codes are used to access your account when you lose access to your 2FA " -"device. Each code can only be used once." +"Recovery codes are used to access your account when you lose access to your " +"2FA device. Each code can only be used once." msgstr "" -"Коды восстановления используются для доступа к аккаунту при утере 2FA-устройства. " -"Каждый код можно использовать только один раз." +"Коды восстановления используются для доступа к аккаунту при утере 2FA-" +"устройства. Каждый код можно использовать только один раз." #: src/views/preference/CertSettings.vue:37 msgid "Recursive Nameservers" @@ -2007,7 +2384,8 @@ msgstr "Регистрация" #: src/views/certificate/ACMEUser.vue:56 msgid "" -"Register a user or use this account to issue a certificate through an HTTP proxy." +"Register a user or use this account to issue a certificate through an HTTP " +"proxy." msgstr "" #: src/views/certificate/ACMEUser.vue:106 @@ -2071,7 +2449,8 @@ msgid "Removed successfully" msgstr "Успешно удалено" #: src/views/config/components/ConfigName.vue:48 -#: src/views/config/components/Rename.vue:54 src/views/config/ConfigList.vue:166 +#: src/views/config/components/Rename.vue:54 +#: src/views/config/ConfigList.vue:166 #: src/views/site/ngx_conf/NgxUpstream.vue:125 #: src/views/site/site_edit/components/ConfigName.vue:44 #: src/views/stream/components/ConfigName.vue:44 @@ -2144,7 +2523,8 @@ msgstr "Переименовано успешно" msgid "Renamed successfully" msgstr "Переименовано успешно" -#: src/views/certificate/RenewCert.vue:45 src/views/certificate/RenewCert.vue:49 +#: src/views/certificate/RenewCert.vue:45 +#: src/views/certificate/RenewCert.vue:49 msgid "Renew Certificate" msgstr "Обновить сертификат" @@ -2185,6 +2565,21 @@ msgstr "Перезапуск" msgid "Restarting" msgstr "Перезапускается" +#: src/views/system/Backup/SystemRestore.vue:81 +#, fuzzy +msgid "Restore completed successfully" +msgstr "Удалено успешно" + +#: src/views/system/Backup/SystemRestore.vue:165 +#, fuzzy +msgid "Restore Nginx Configuration" +msgstr "Ошибка разбора конфигурации Nginx" + +#: src/views/system/Backup/SystemRestore.vue:176 +#, fuzzy +msgid "Restore Nginx UI Configuration" +msgstr "Ошибка разбора конфигурации Nginx" + #: src/views/preference/AuthSettings.vue:107 msgid "RP Display Name" msgstr "" @@ -2216,7 +2611,8 @@ msgstr "Выполняется" #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:127 #: src/views/site/site_edit/components/ConfigName.vue:52 #: src/views/site/site_edit/SiteEdit.vue:271 -#: src/views/stream/components/ConfigName.vue:52 src/views/stream/StreamEdit.vue:253 +#: src/views/stream/components/ConfigName.vue:52 +#: src/views/stream/StreamEdit.vue:253 msgid "Save" msgstr "Сохранить" @@ -2226,7 +2622,7 @@ msgstr "Сохранить директиву" #: src/views/config/ConfigEditor.vue:171 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:41 -#: src/views/site/SiteAdd.vue:46 +#: src/views/site/site_add/SiteAdd.vue:46 msgid "Save error %{msg}" msgstr "Ошибка сохранения %{msg}" @@ -2277,7 +2673,8 @@ msgstr "Сохранено успешно" #: src/views/config/ConfigEditor.vue:167 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:39 -#: src/views/site/site_edit/SiteEdit.vue:152 src/views/site/SiteAdd.vue:37 +#: src/views/site/site_add/SiteAdd.vue:37 +#: src/views/site/site_edit/SiteEdit.vue:152 #: src/views/stream/StreamEdit.vue:139 msgid "Saved successfully" msgstr "Успешно сохранено" @@ -2285,8 +2682,8 @@ msgstr "Успешно сохранено" #: src/views/preference/components/TOTP.vue:69 msgid "Scan the QR code with your mobile phone to add the account to the app." msgstr "" -"Отсканируйте QR-код с помощью мобильного телефона, чтобы добавить учетную запись в " -"приложение." +"Отсканируйте QR-код с помощью мобильного телефона, чтобы добавить учетную " +"запись в приложение." #: src/views/certificate/DNSChallenge.vue:90 msgid "SDK" @@ -2296,11 +2693,20 @@ msgstr "SDK" msgid "Secret has been copied" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:150 +msgid "Security Token" +msgstr "" + +#: src/views/system/Backup/BackupCreator.vue:94 +#, fuzzy +msgid "Security Token Information" +msgstr "Неверный код восстановления" + #: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:189 msgid "Selector" msgstr "Выбор" -#: src/routes/index.ts:283 src/views/system/SelfCheck/SelfCheck.vue:42 +#: src/routes/modules/system.ts:19 src/views/system/SelfCheck/SelfCheck.vue:42 msgid "Self Check" msgstr "" @@ -2327,11 +2733,11 @@ msgstr "Сессия не найдена" #: src/views/preference/CertSettings.vue:33 msgid "" -"Set the recursive nameservers to override the systems nameservers for the step of " -"DNS challenge." +"Set the recursive nameservers to override the systems nameservers for the " +"step of DNS challenge." msgstr "" -"Установите рекурсивные серверы имен, чтобы переопределить системные серверы имен " -"для шага проверки DNS." +"Установите рекурсивные серверы имен, чтобы переопределить системные серверы " +"имен для шага проверки DNS." #: src/language/constants.ts:11 msgid "Setting DNS01 challenge provider" @@ -2347,14 +2753,14 @@ msgstr "Настройка провайдера проверки HTTP01" #: src/constants/errors/nginx_log.ts:8 msgid "" -"Settings.NginxLogSettings.AccessLogPath is empty, refer to https://nginxui.com/" -"guide/config-nginx.html for more information" +"Settings.NginxLogSettings.AccessLogPath is empty, refer to https://nginxui." +"com/guide/config-nginx.html for more information" msgstr "" #: src/constants/errors/nginx_log.ts:7 msgid "" -"Settings.NginxLogSettings.ErrorLogPath is empty, refer to https://nginxui.com/" -"guide/config-nginx.html for more information" +"Settings.NginxLogSettings.ErrorLogPath is empty, refer to https://nginxui." +"com/guide/config-nginx.html for more information" msgstr "" #: src/components/SensitiveString/SensitiveString.vue:40 @@ -2369,11 +2775,12 @@ msgstr "" msgid "Single Directive" msgstr "Одиночная Директива" -#: src/routes/index.ts:71 src/views/site/site_category/SiteCategory.vue:10 +#: src/routes/modules/sites.ts:34 +#: src/views/site/site_category/SiteCategory.vue:10 msgid "Site Categories" msgstr "" -#: src/views/site/SiteAdd.vue:147 +#: src/views/site/site_add/SiteAdd.vue:147 #, fuzzy msgid "Site Config Created Successfully" msgstr "Конфигурация домена успешно создана" @@ -2383,7 +2790,7 @@ msgstr "Конфигурация домена успешно создана" msgid "Site is enabled" msgstr "Авто Сертификат" -#: src/routes/index.ts:224 +#: src/routes/modules/nginx_log.ts:31 msgid "Site Logs" msgstr "Журналы сайта" @@ -2397,7 +2804,7 @@ msgstr "Файл не найден" msgid "Sites Directory" msgstr "Каталог" -#: src/routes/index.ts:56 +#: src/routes/modules/sites.ts:19 msgid "Sites List" msgstr "Список сайтов" @@ -2435,10 +2842,14 @@ msgstr "SSO Вход" msgid "Stable" msgstr "Стабильный" +#: src/views/system/Backup/SystemRestore.vue:187 +msgid "Start Restore" +msgstr "" + #: src/views/certificate/ACMEUser.vue:65 #: src/views/certificate/CertificateList/certColumns.tsx:68 -#: src/views/environment/envColumns.tsx:44 src/views/site/site_list/columns.tsx:42 -#: src/views/stream/StreamList.vue:22 +#: src/views/environment/envColumns.tsx:44 +#: src/views/site/site_list/columns.tsx:42 src/views/stream/StreamList.vue:22 msgid "Status" msgstr "Статус" @@ -2481,10 +2892,14 @@ msgstr "Успех" #: src/views/system/SelfCheck/SelfCheck.vue:78 msgid "" -"Support communication with the backend through the WebSocket protocol. If your " -"Nginx UI is being used via an Nginx reverse proxy, please refer to this link to " -"write the corresponding configuration file: https://nginxui.com/guide/nginx-proxy-" -"example.html" +"Support communication with the backend through the WebSocket protocol. If " +"your Nginx UI is being used via an Nginx reverse proxy, please refer to this " +"link to write the corresponding configuration file: https://nginxui.com/" +"guide/nginx-proxy-example.html" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:140 +msgid "Supported file type: .zip" msgstr "" #: src/views/dashboard/ServerAnalytic.vue:236 @@ -2544,7 +2959,7 @@ msgstr "Ошибка синхронизации конфигурации" msgid "Sync Config Success" msgstr "Синхронизация конфигурации успешна" -#: src/views/site/site_category/SiteCategory.vue:17 +#: src/views/site/site_category/SiteCategory.vue:18 #, fuzzy msgid "Sync Nodes" msgstr "Синхронизировать с" @@ -2563,20 +2978,30 @@ msgstr "Синхронизировать с" msgid "Synchronization" msgstr "" -#: src/routes/index.ts:275 +#: src/routes/modules/system.ts:11 msgid "System" msgstr "Система" +#: src/views/system/Backup/BackupCreator.vue:71 +#, fuzzy +msgid "System Backup" +msgstr "Система" + #: src/views/certificate/ACMEUserSelector.vue:88 msgid "System Initial User" msgstr "Первоначальный пользователь системы" +#: src/views/system/Backup/SystemRestore.vue:117 +#, fuzzy +msgid "System Restore" +msgstr "Система" + #: src/constants/errors/self_check.ts:2 #, fuzzy msgid "Task not found" msgstr "Файл не найден" -#: src/routes/index.ts:194 src/views/terminal/Terminal.vue:114 +#: src/routes/modules/terminal.ts:10 src/views/terminal/Terminal.vue:114 msgid "Terminal" msgstr "Терминал" @@ -2586,12 +3011,13 @@ msgstr "Терминальная команда запуска" #: src/views/site/cert/components/AutoCertStepOne.vue:49 msgid "" -"The certificate for the domain will be checked 30 minutes, and will be renewed if " -"it has been more than 1 week or the period you set in settings since it was last " -"issued." +"The certificate for the domain will be checked 30 minutes, and will be " +"renewed if it has been more than 1 week or the period you set in settings " +"since it was last issued." msgstr "" -"Сертификат для домена будет проверен через 30 минут и обновлен, если прошло более " -"1 недели или периода, установленного в настройках, с момента его последней выдачи." +"Сертификат для домена будет проверен через 30 минут и обновлен, если прошло " +"более 1 недели или периода, установленного в настройках, с момента его " +"последней выдачи." #: src/views/other/Install.vue:54 msgid "The filename cannot contain the following characters: %{c}" @@ -2600,10 +3026,11 @@ msgstr "Имя файла не может содержать такой симв #: src/views/preference/BasicSettings.vue:54 #, fuzzy msgid "" -"The ICP Number should only contain letters, unicode, numbers, hyphens, dashes, " -"colons, and dots." +"The ICP Number should only contain letters, unicode, numbers, hyphens, " +"dashes, colons, and dots." msgstr "" -"Имя модели должно содержать только буквы, юникод, цифры, дефисы, тире и точки." +"Имя модели должно содержать только буквы, юникод, цифры, дефисы, тире и " +"точки." #: src/views/certificate/CertificateEditor.vue:214 msgid "The input is not a SSL Certificate" @@ -2614,26 +3041,29 @@ msgid "The input is not a SSL Certificate Key" msgstr "Введенные данные не являются ключом SSL сертификата" #: src/constants/errors/nginx_log.ts:2 -msgid "The log path is not under the paths in settings.NginxSettings.LogDirWhiteList" +msgid "" +"The log path is not under the paths in settings.NginxSettings.LogDirWhiteList" msgstr "" #: src/views/preference/OpenAISettings.vue:23 #, fuzzy msgid "" -"The model name should only contain letters, unicode, numbers, hyphens, dashes, " -"colons, and dots." +"The model name should only contain letters, unicode, numbers, hyphens, " +"dashes, colons, and dots." msgstr "" -"Имя модели должно содержать только буквы, юникод, цифры, дефисы, тире и точки." +"Имя модели должно содержать только буквы, юникод, цифры, дефисы, тире и " +"точки." #: src/views/preference/BasicSettings.vue:33 #, fuzzy msgid "" -"The node name should only contain letters, unicode, numbers, hyphens, dashes, " -"colons, and dots." +"The node name should only contain letters, unicode, numbers, hyphens, " +"dashes, colons, and dots." msgstr "" -"Имя модели должно содержать только буквы, юникод, цифры, дефисы, тире и точки." +"Имя модели должно содержать только буквы, юникод, цифры, дефисы, тире и " +"точки." -#: src/views/site/SiteAdd.vue:120 +#: src/views/site/site_add/SiteAdd.vue:120 #, fuzzy msgid "The parameter of server_name is required" msgstr "server_name параметр обязателен" @@ -2649,30 +3079,32 @@ msgstr "Путь существует, но файл не является пр #: src/views/preference/BasicSettings.vue:66 #, fuzzy msgid "" -"The Public Security Number should only contain letters, unicode, numbers, hyphens, " -"dashes, colons, and dots." +"The Public Security Number should only contain letters, unicode, numbers, " +"hyphens, dashes, colons, and dots." msgstr "" -"Имя сервера должно содержать только буквы, юникод, цифры, дефисы, тире и точки." +"Имя сервера должно содержать только буквы, юникод, цифры, дефисы, тире и " +"точки." #: src/views/dashboard/Environments.vue:148 msgid "" -"The remote Nginx UI version is not compatible with the local Nginx UI version. To " -"avoid potential errors, please upgrade the remote Nginx UI to match the local " -"version." +"The remote Nginx UI version is not compatible with the local Nginx UI " +"version. To avoid potential errors, please upgrade the remote Nginx UI to " +"match the local version." msgstr "" "Удаленная версия Nginx UI не совместима с локальной версией Nginx UI. Чтобы " -"избежать потенциальных ошибок, пожалуйста, обновите удаленную версию Nginx UI до " -"соответствия с локальной версией." +"избежать потенциальных ошибок, пожалуйста, обновите удаленную версию Nginx " +"UI до соответствия с локальной версией." #: src/views/site/cert/components/AutoCertStepOne.vue:44 msgid "" -"The server_name in the current configuration must be the domain name you need to " -"get the certificate, supportmultiple domains." +"The server_name in the current configuration must be the domain name you " +"need to get the certificate, supportmultiple domains." msgstr "" -"server_name в текущей конфигурации должен быть доменным именем, для которого вам " -"нужно получить сертификат, поддержка нескольких доменов." +"server_name в текущей конфигурации должен быть доменным именем, для которого " +"вам нужно получить сертификат, поддержка нескольких доменов." -#: src/views/preference/BasicSettings.vue:42 src/views/preference/CertSettings.vue:19 +#: src/views/preference/BasicSettings.vue:42 +#: src/views/preference/CertSettings.vue:19 msgid "The url is invalid" msgstr "URL недействителен" @@ -2687,9 +3119,9 @@ msgstr "Имя пользователя или пароль неверны" #: src/views/preference/components/RecoveryCodes.vue:104 msgid "" -"These codes are the last resort for accessing your account in case you lose your " -"password and second factors. If you cannot find these codes, you will lose access " -"to your account." +"These codes are the last resort for accessing your account in case you lose " +"your password and second factors. If you cannot find these codes, you will " +"lose access to your account." msgstr "" #: src/views/certificate/CertificateEditor.vue:102 @@ -2723,18 +3155,40 @@ msgstr "Это поле обязательно к заполнению" #: src/constants/form_errors.ts:6 #, fuzzy -msgid "This field should only contain letters, unicode characters, numbers, and -_." +msgid "" +"This field should only contain letters, unicode characters, numbers, and -_." +msgstr "" +"Имя модели должно содержать только буквы, юникод, цифры, дефисы, тире и " +"точки." + +#: src/views/system/Backup/BackupCreator.vue:141 +msgid "" +"This token will only be shown once and cannot be retrieved later. Please " +"make sure to save it in a secure location." msgstr "" -"Имя модели должно содержать только буквы, юникод, цифры, дефисы, тире и точки." #: src/constants/form_errors.ts:4 msgid "This value is already taken" msgstr "" -#: src/views/environment/BatchUpgrader.vue:182 -msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}." +#: src/views/system/Backup/SystemRestore.vue:169 +msgid "" +"This will restore all Nginx configuration files. Nginx will restart after " +"the restoration is complete." msgstr "" -"Это обновит или переустановит интерфейс Nginx на %{nodeNames} до версии %{version}." + +#: src/views/system/Backup/SystemRestore.vue:180 +msgid "" +"This will restore configuration files and database. Nginx UI will restart " +"after the restoration is complete." +msgstr "" + +#: src/views/environment/BatchUpgrader.vue:182 +msgid "" +"This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}." +msgstr "" +"Это обновит или переустановит интерфейс Nginx на %{nodeNames} до версии " +"%{version}." #: src/views/preference/AuthSettings.vue:124 msgid "Throttle" @@ -2752,34 +3206,36 @@ msgstr "Заголовок" #: src/views/preference/components/TOTP.vue:68 msgid "" -"To enable it, you need to install the Google or Microsoft Authenticator app on " -"your mobile phone." +"To enable it, you need to install the Google or Microsoft Authenticator app " +"on your mobile phone." msgstr "" "Чтобы включить это, вам нужно установить приложение Google или Microsoft " "Authenticator на свой мобильный телефон." #: src/views/preference/components/AddPasskey.vue:89 msgid "" -"To ensure security, Webauthn configuration cannot be added through the UI. Please " -"manually configure the following in the app.ini configuration file and restart " -"Nginx UI." +"To ensure security, Webauthn configuration cannot be added through the UI. " +"Please manually configure the following in the app.ini configuration file " +"and restart Nginx UI." msgstr "" #: src/views/site/ngx_conf/NgxConfigEditor.vue:45 msgid "" -"To make sure the certification auto-renewal can work normally, we need to add a " -"location which can proxy the request from authority to backend, and we need to " -"save this file and reload the Nginx. Are you sure you want to continue?" +"To make sure the certification auto-renewal can work normally, we need to " +"add a location which can proxy the request from authority to backend, and we " +"need to save this file and reload the Nginx. Are you sure you want to " +"continue?" msgstr "" "Чтобы убедиться, что автоматическое обновление сертификата может работать " -"нормально, нам нужно добавить местоположение, которое может проксировать запрос от " -"авторитета к бэкенду, и нам нужно сохранить этот файл и перезагрузить Nginx. Вы " -"уверены, что хотите продолжить?" +"нормально, нам нужно добавить местоположение, которое может проксировать " +"запрос от авторитета к бэкенду, и нам нужно сохранить этот файл и " +"перезагрузить Nginx. Вы уверены, что хотите продолжить?" #: src/views/preference/OpenAISettings.vue:36 msgid "" -"To use a local large model, deploy it with ollama, vllm or lmdeploy. They provide " -"an OpenAI-compatible API endpoint, so just set the baseUrl to your local API." +"To use a local large model, deploy it with ollama, vllm or lmdeploy. They " +"provide an OpenAI-compatible API endpoint, so just set the baseUrl to your " +"local API." msgstr "" #: src/views/preference/OpenAISettings.vue:61 @@ -2822,9 +3278,11 @@ msgstr "Тип" msgid "Update successfully" msgstr "Успешно обновлено" -#: src/views/certificate/ACMEUser.vue:88 src/views/certificate/DNSCredential.vue:27 +#: src/views/certificate/ACMEUser.vue:88 +#: src/views/certificate/DNSCredential.vue:27 #: src/views/config/configColumns.tsx:34 src/views/config/ConfigEditor.vue:276 -#: src/views/environment/envColumns.tsx:90 src/views/site/site_category/columns.ts:22 +#: src/views/environment/envColumns.tsx:90 +#: src/views/site/site_category/columns.ts:22 #: src/views/site/site_edit/RightSettings.vue:100 #: src/views/site/site_list/columns.tsx:69 #: src/views/stream/components/RightSettings.vue:85 @@ -2836,7 +3294,7 @@ msgstr "Обновлено в" msgid "Updated successfully" msgstr "Успешно обновлено" -#: src/routes/index.ts:297 src/views/environment/Environment.vue:66 +#: src/routes/modules/system.ts:40 src/views/environment/Environment.vue:66 #: src/views/system/Upgrade.vue:143 src/views/system/Upgrade.vue:226 msgid "Upgrade" msgstr "Обновление" @@ -2900,6 +3358,10 @@ msgstr "Имя пользователя (*)" msgid "Valid" msgstr "Действительный" +#: src/views/system/Backup/SystemRestore.vue:159 +msgid "Verify Backup File Integrity" +msgstr "" + #: src/views/environment/envColumns.tsx:31 msgid "Version" msgstr "Версия" @@ -2934,10 +3396,19 @@ msgstr "Просмотр" #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33 #: src/views/notification/notificationColumns.tsx:22 -#: src/views/preference/components/AddPasskey.vue:82 src/views/site/SiteAdd.vue:115 +#: src/views/preference/components/AddPasskey.vue:82 +#: src/views/site/site_add/SiteAdd.vue:115 +#: src/views/system/Backup/BackupCreator.vue:138 msgid "Warning" msgstr "Внимание" +#: src/views/system/Backup/SystemRestore.vue:121 +msgid "" +"Warning: Restore operation will overwrite current configurations. Make sure " +"you have a valid backup file and security token, and carefully select what " +"to restore." +msgstr "" + #: src/views/certificate/DNSCredential.vue:56 msgid "" "We will add one or more TXT records to the DNS records of your domain for " @@ -2965,19 +3436,20 @@ msgstr "Настройки WebAuthn не настроены" #: src/views/certificate/ACMEUser.vue:83 msgid "" "When Enabled, Nginx UI will automatically re-register users upon startup. " -"Generally, do not enable this unless you are in a dev environment and using Pebble " -"as CA." +"Generally, do not enable this unless you are in a dev environment and using " +"Pebble as CA." msgstr "" #: src/views/site/site_edit/RightSettings.vue:116 msgid "" -"When you enable/disable, delete, or save this site, the nodes set in the site " -"category and the nodes selected below will be synchronized." +"When you enable/disable, delete, or save this site, the nodes set in the " +"site category and the nodes selected below will be synchronized." msgstr "" #: src/views/preference/components/RecoveryCodes.vue:140 msgid "" -"When you generate new recovery codes, you must download or print the new codes." +"When you generate new recovery codes, you must download or print the new " +"codes." msgstr "" #: src/views/dashboard/ServerAnalytic.vue:37 @@ -2993,7 +3465,8 @@ msgstr "Запись закрытого ключа сертификата на msgid "Writing certificate to disk" msgstr "Запись сертификата на диск" -#: src/views/preference/AuthSettings.vue:163 src/views/preference/CertSettings.vue:69 +#: src/views/preference/AuthSettings.vue:163 +#: src/views/preference/CertSettings.vue:69 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:96 #: src/views/site/ngx_conf/LocationEditor.vue:87 msgid "Yes" @@ -3009,11 +3482,13 @@ msgstr "Вы можете проверить обновление Nginx UI на #: src/views/preference/components/AddPasskey.vue:87 msgid "" -"You have not configured the settings of Webauthn, so you cannot add a passkey." +"You have not configured the settings of Webauthn, so you cannot add a " +"passkey." msgstr "" #: src/views/preference/components/RecoveryCodes.vue:81 -msgid "You have not enabled 2FA yet. Please enable 2FA to generate recovery codes." +msgid "" +"You have not enabled 2FA yet. Please enable 2FA to generate recovery codes." msgstr "" #: src/views/preference/components/RecoveryCodes.vue:94 @@ -3022,8 +3497,8 @@ msgstr "" #: src/views/preference/components/RecoveryCodes.vue:91 msgid "" -"Your current recovery code might be outdated and insecure. Please generate new " -"recovery codes at your earliest convenience to ensure security." +"Your current recovery code might be outdated and insecure. Please generate " +"new recovery codes at your earliest convenience to ensure security." msgstr "" #: src/views/preference/components/RecoveryCodes.vue:142 @@ -3035,6 +3510,10 @@ msgstr "Ваши старые коды больше не будут работа msgid "Your passkeys" msgstr "" +#, fuzzy +#~ msgid "Restart Required" +#~ msgstr "Перезапускается" + #~ msgid "Deploy %{conf_name} to %{node_name} successfully" #~ msgstr "Успешно развернуто %{conf_name} на %{node_name}" @@ -3071,49 +3550,51 @@ msgstr "" #~ msgid "Enable successfully" #~ msgstr "Включено успешно" -#~ msgid "Please select at least one node!" -#~ msgstr "Пожалуйста, выберите хотя бы один узел!" - #, fuzzy #~ msgid "Please upgrade the remote Nginx UI to the latest version" #~ msgstr "" -#~ "Синхронизация конфигурации %{cert_name} с %{env_name} не удалась, пожалуйста, " -#~ "обновите удаленный Nginx UI до последней версии" +#~ "Синхронизация конфигурации %{cert_name} с %{env_name} не удалась, " +#~ "пожалуйста, обновите удаленный Nginx UI до последней версии" #, fuzzy #~ msgid "Remove site %{site} from %{node} error, response: %{resp}" #~ msgstr "Удалить сайт: %{site_name}" #~ msgid "" -#~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: %{resp}" -#~ msgstr "" -#~ "Переименование %{orig_path} в %{new_path} на %{env_name} не удалось, ответ: " +#~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: " #~ "%{resp}" +#~ msgstr "" +#~ "Переименование %{orig_path} в %{new_path} на %{env_name} не удалось, " +#~ "ответ: %{resp}" #, fuzzy -#~ msgid "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}" +#~ msgid "" +#~ "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}" #~ msgstr "Переименование %{orig_path} в %{new_path} на %{env_name} успешно" #, fuzzy #~ msgid "Save site %{site} to %{node} error, response: %{resp}" #~ msgstr "" -#~ "Синхронизация сертификата %{cert_name} с %{env_name} не удалась, ответ: %{resp}" +#~ "Синхронизация сертификата %{cert_name} с %{env_name} не удалась, ответ: " +#~ "%{resp}" #~ msgid "" -#~ "Sync Certificate %{cert_name} to %{env_name} failed, please upgrade the remote " -#~ "Nginx UI to the latest version" +#~ "Sync Certificate %{cert_name} to %{env_name} failed, please upgrade the " +#~ "remote Nginx UI to the latest version" #~ msgstr "" -#~ "Синхронизация сертификата %{cert_name} с %{env_name} не удалась, пожалуйста, " -#~ "обновите удаленный интерфейс Nginx до последней версии" +#~ "Синхронизация сертификата %{cert_name} с %{env_name} не удалась, " +#~ "пожалуйста, обновите удаленный интерфейс Nginx до последней версии" -#~ msgid "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}" +#~ msgid "" +#~ "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}" #~ msgstr "" -#~ "Синхронизация сертификата %{cert_name} с %{env_name} не удалась, ответ: %{resp}" +#~ "Синхронизация сертификата %{cert_name} с %{env_name} не удалась, ответ: " +#~ "%{resp}" #~ msgid "Sync config %{config_name} to %{env_name} failed, response: %{resp}" #~ msgstr "" -#~ "Синхронизация конфигурации %{config_name} с %{env_name} не удалась, ответ: " -#~ "%{resp}" +#~ "Синхронизация конфигурации %{config_name} с %{env_name} не удалась, " +#~ "ответ: %{resp}" #~ msgid "Target" #~ msgstr "Цель" @@ -3128,7 +3609,8 @@ msgstr "" #~ msgstr "Файл" #~ msgid "" -#~ "If you lose your mobile phone, you can use the recovery code to reset your 2FA." +#~ "If you lose your mobile phone, you can use the recovery code to reset " +#~ "your 2FA." #~ msgstr "" #~ "Если вы потеряете свой мобильный телефон, вы можете использовать код " #~ "восстановления для сброса 2FA." @@ -3142,17 +3624,18 @@ msgstr "" #~ msgid "Server error" #~ msgstr "Ошибка сервера" -#~ msgid "The recovery code is only displayed once, please save it in a safe place." +#~ msgid "" +#~ "The recovery code is only displayed once, please save it in a safe place." #~ msgstr "" -#~ "Код восстановления отображается только один раз, пожалуйста, сохраните его в " -#~ "безопасном месте." +#~ "Код восстановления отображается только один раз, пожалуйста, сохраните " +#~ "его в безопасном месте." #~ msgid "Too many login failed attempts, please try again later" #~ msgstr "Слишком много неудачных попыток входа, попробуйте позже" #~ msgid "" -#~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, please upgrade the " -#~ "remote Nginx UI to the latest version" +#~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, please upgrade " +#~ "the remote Nginx UI to the latest version" #~ msgstr "" #~ "Переименование %{orig_path} в %{new_path} на %{env_name} не удалось, " #~ "пожалуйста, обновите удаленный интерфейс Nginx до последней версии" diff --git a/app/src/language/tr_TR/app.po b/app/src/language/tr_TR/app.po index 287264cc..a892f49f 100644 --- a/app/src/language/tr_TR/app.po +++ b/app/src/language/tr_TR/app.po @@ -20,15 +20,15 @@ msgstr "İki aşamalı kimlik doğrulaması(2FA)" msgid "2FA Settings" msgstr "2FA Ayarları" -#: src/routes/index.ts:290 +#: src/routes/modules/system.ts:26 msgid "About" msgstr "Hakkında" -#: src/routes/index.ts:210 src/views/site/ngx_conf/LogEntry.vue:75 +#: src/routes/modules/nginx_log.ts:17 src/views/site/ngx_conf/LogEntry.vue:75 msgid "Access Logs" msgstr "Erişim Günlükleri" -#: src/routes/index.ts:148 src/views/certificate/ACMEUser.vue:113 +#: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:113 #: src/views/certificate/ACMEUserSelector.vue:85 msgid "ACME User" msgstr "ACME Kullanıcısı" @@ -40,7 +40,7 @@ msgstr "ACME Kullanıcısı" #: src/views/environment/envColumns.tsx:97 #: src/views/notification/notificationColumns.tsx:65 #: src/views/preference/AuthSettings.vue:30 -#: src/views/site/site_category/columns.ts:29 +#: src/views/site/site_category/columns.ts:28 #: src/views/site/site_list/columns.tsx:76 src/views/stream/StreamList.vue:49 #: src/views/user/userColumns.tsx:60 msgid "Action" @@ -61,7 +61,7 @@ msgstr "Ekle" msgid "Add a passkey" msgstr "Geçiş anahtarı ekleme" -#: src/routes/index.ts:118 src/views/config/ConfigEditor.vue:144 +#: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:144 #: src/views/config/ConfigEditor.vue:204 msgid "Add Configuration" msgstr "Yapılandırma Ekle" @@ -75,7 +75,7 @@ msgstr "Direktifi Aşağıya Ekleyin" msgid "Add Location" msgstr "Konum ekle" -#: src/routes/index.ts:63 src/views/site/SiteAdd.vue:89 +#: src/routes/modules/sites.ts:26 src/views/site/site_add/SiteAdd.vue:89 msgid "Add Site" msgstr "Site Ekle" @@ -252,6 +252,10 @@ msgstr "Otomatik yenileme %{name} için devre dışı" msgid "Auto-renewal enabled for %{name}" msgstr "Otomatik yenileme %{name} için etkinleştirildi" +#: src/views/system/Backup/SystemRestore.vue:92 +msgid "Automatic Restart" +msgstr "" + #: src/views/certificate/CertificateEditor.vue:255 #: src/views/config/ConfigEditor.vue:213 src/views/config/ConfigList.vue:106 #: src/views/config/ConfigList.vue:180 src/views/nginx_log/NginxLog.vue:173 @@ -268,6 +272,25 @@ msgstr "Ana Sayfaya Dön" msgid "Back to list" msgstr "Listeye geri dön" +#: src/routes/modules/system.ts:33 +#, fuzzy +msgid "Backup" +msgstr "Geri" + +#: src/views/system/Backup/SystemRestore.vue:100 +msgid "Backup file integrity check failed, it may have been tampered with" +msgstr "" + +#: src/constants/errors/backup.ts:39 +#, fuzzy +msgid "Backup file not found: {0}" +msgstr "Dosya bulunamadı" + +#: src/views/system/Backup/BackupCreator.vue:42 +#, fuzzy +msgid "Backup has been downloaded successfully" +msgstr "Nginx başarıyla yeniden yüklendi" + #: src/views/preference/AuthSettings.vue:129 msgid "Ban Threshold Minutes" msgstr "Yasaklama Eşiği Süresi (Dakika)" @@ -280,7 +303,7 @@ msgstr "Yasaklı IP'ler" msgid "Banned Until" msgstr "Şu Zamana Kadar Yasaklı" -#: src/views/site/SiteAdd.vue:95 +#: src/views/site/site_add/SiteAdd.vue:95 msgid "Base information" msgstr "Temel bilgiler" @@ -393,12 +416,12 @@ msgid_plural "Certificates Status" msgstr[0] "Sertifika Durumu" msgstr[1] "Sertifikaların Durumu" -#: src/routes/index.ts:139 +#: src/routes/modules/certificates.ts:11 #: src/views/certificate/CertificateList/Certificate.vue:13 msgid "Certificates" msgstr "Sertifikalar" -#: src/routes/index.ts:156 +#: src/routes/modules/certificates.ts:28 msgid "Certificates List" msgstr "Sertifika Listesi" @@ -468,6 +491,10 @@ msgstr "Temizle" msgid "Cleared successfully" msgstr "Başarıyla temizlendi" +#: src/views/system/Backup/SystemRestore.vue:137 +msgid "Click or drag backup file to this area to upload" +msgstr "" + #: src/views/preference/components/TOTP.vue:110 msgid "Click to copy" msgstr "" @@ -483,6 +510,11 @@ msgstr "Komut" msgid "Comments" msgstr "Yorumlar" +#: src/constants/errors/backup.ts:13 +#, fuzzy +msgid "Config path is empty" +msgstr "Yapılandırma Şablonları" + #: src/views/site/ngx_conf/config_template/ConfigTemplate.vue:84 msgid "Config Templates" msgstr "Yapılandırma Şablonları" @@ -491,7 +523,7 @@ msgstr "Yapılandırma Şablonları" msgid "Configuration file is test successful" msgstr "Yapılandırma dosyası başarıyla test edildi" -#: src/views/site/SiteAdd.vue:101 +#: src/views/site/site_add/SiteAdd.vue:101 msgid "Configuration Name" msgstr "Yapılandırma Adı" @@ -499,7 +531,7 @@ msgstr "Yapılandırma Adı" msgid "Configurations" msgstr "Yapılandırmalar" -#: src/views/site/SiteAdd.vue:96 +#: src/views/site/site_add/SiteAdd.vue:96 msgid "Configure SSL" msgstr "SSL'yi Yapılandırma" @@ -523,7 +555,13 @@ msgstr "İçerik" msgid "Copied" msgstr "Kopyalandı" +#: src/views/system/Backup/BackupCreator.vue:128 +#, fuzzy +msgid "Copied!" +msgstr "Kopyalandı" + #: src/components/SensitiveString/SensitiveString.vue:37 +#: src/views/system/Backup/BackupCreator.vue:128 msgid "Copy" msgstr "Kopya" @@ -548,10 +586,15 @@ msgstr "CPU:" msgid "Create" msgstr "Oluştur" -#: src/views/site/SiteAdd.vue:157 +#: src/views/site/site_add/SiteAdd.vue:157 msgid "Create Another" msgstr "Bir Başka Oluştur" +#: src/views/system/Backup/BackupCreator.vue:86 +#, fuzzy +msgid "Create Backup" +msgstr "Oluşturulma Tarihi" + #: src/views/config/ConfigList.vue:116 msgid "Create File" msgstr "Dosya Oluştur" @@ -560,9 +603,15 @@ msgstr "Dosya Oluştur" msgid "Create Folder" msgstr "Klasör Ekle" +#: src/views/system/Backup/BackupCreator.vue:75 +msgid "" +"Create system backups including Nginx configuration and Nginx UI settings. " +"Backup files will be automatically downloaded to your computer." +msgstr "" + #: src/views/notification/notificationColumns.tsx:58 #: src/views/preference/components/Passkey.vue:95 -#: src/views/site/site_category/columns.ts:15 src/views/user/userColumns.tsx:48 +#: src/views/site/site_category/columns.ts:16 src/views/user/userColumns.tsx:48 msgid "Created at" msgstr "Oluşturulma Tarihi" @@ -606,7 +655,7 @@ msgid "" "indicator." msgstr "Ortam göstergesinde görüntülenecek yerel sunucu adını özelleştirin." -#: src/routes/index.ts:38 src/views/config/ConfigEditor.vue:134 +#: src/routes/modules/dashboard.ts:10 src/views/config/ConfigEditor.vue:134 #: src/views/config/ConfigEditor.vue:97 src/views/config/ConfigList.vue:64 msgid "Dashboard" msgstr "Kontrol Paneli" @@ -810,7 +859,8 @@ msgstr "Başarıyla devre dışı bırakıldı" msgid "Disk IO" msgstr "Disk IO" -#: src/routes/index.ts:184 src/views/certificate/DNSCredential.vue:40 +#: src/routes/modules/certificates.ts:56 +#: src/views/certificate/DNSCredential.vue:40 msgid "DNS Credentials" msgstr "DNS Kimlik Bilgileri" @@ -920,15 +970,15 @@ msgstr "Düzenle %{n}" msgid "Edit %{n}" msgstr "Düzenle %{n}" -#: src/routes/index.ts:128 src/views/config/ConfigEditor.vue:204 +#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:204 msgid "Edit Configuration" msgstr "Yapılandırmayı Düzenle" -#: src/routes/index.ts:78 +#: src/routes/modules/sites.ts:41 msgid "Edit Site" msgstr "Siteyi Düzenle" -#: src/routes/index.ts:98 +#: src/routes/modules/streams.ts:19 msgid "Edit Stream" msgstr "Akışı Düzenle" @@ -953,7 +1003,7 @@ msgstr "2FA'yı başarıyla etkinleştirildi" msgid "Enable auto-renewal failed for %{name}" msgstr "%{name} için otomatik yenilemeyi etkinleştirme başarısız oldu" -#: src/views/site/SiteAdd.vue:43 +#: src/views/site/site_add/SiteAdd.vue:43 msgid "Enable failed" msgstr "Etkinleştirme başarısız" @@ -1026,8 +1076,9 @@ msgstr "TOTP'yi Etkinleştir" msgid "Enabled" msgstr "Etkin" +#: src/views/site/site_add/SiteAdd.vue:40 #: src/views/site/site_edit/RightSettings.vue:33 -#: src/views/site/site_list/SiteList.vue:46 src/views/site/SiteAdd.vue:40 +#: src/views/site/site_list/SiteList.vue:46 #: src/views/stream/components/RightSettings.vue:29 #: src/views/stream/StreamList.vue:61 msgid "Enabled successfully" @@ -1041,7 +1092,8 @@ msgstr "Let's Encrypt ile web sitesini şifreleyin" msgid "Environment variables cleaned" msgstr "Ortam değişkenleri temizlendi" -#: src/routes/index.ts:234 src/views/dashboard/Environments.vue:83 +#: src/routes/modules/environments.ts:11 +#: src/views/dashboard/Environments.vue:83 #: src/views/environment/Environment.vue:43 msgid "Environments" msgstr "Ortamlar" @@ -1051,7 +1103,7 @@ msgstr "Ortamlar" msgid "Error" msgstr "Hata" -#: src/routes/index.ts:217 src/views/site/ngx_conf/LogEntry.vue:83 +#: src/routes/modules/nginx_log.ts:24 src/views/site/ngx_conf/LogEntry.vue:83 msgid "Error Logs" msgstr "Hata Günlükleri" @@ -1076,11 +1128,130 @@ msgstr "Dışa Aktar" msgid "Fail to obtain certificate" msgstr "Sertifika alınamadı" +#: src/constants/errors/backup.ts:5 +msgid "Failed to backup Nginx config files: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:4 +msgid "Failed to backup Nginx UI files: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:17 +#, fuzzy +msgid "Failed to calculate hash: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:53 +msgid "Failed to calculate Nginx hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:52 +msgid "Failed to calculate Nginx UI hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:14 +msgid "Failed to copy config file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:15 +msgid "Failed to copy database directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:16 +#, fuzzy +msgid "Failed to copy database file: {0}" +msgstr "Devre dışı bırakılamadı %{msg}" + +#: src/constants/errors/backup.ts:30 +msgid "Failed to copy file content: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:19 +msgid "Failed to copy Nginx config directory: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:9 #, fuzzy msgid "Failed to create backup" msgstr "Etkinleştirilemedi %{msg}" +#: src/constants/errors/backup.ts:12 +#, fuzzy +msgid "Failed to create backup file: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:44 +#, fuzzy +msgid "Failed to create directory: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:46 +#, fuzzy +msgid "Failed to create file: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:6 +#, fuzzy +msgid "Failed to create hash info file: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:45 +#, fuzzy +msgid "Failed to create parent directory: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:32 +msgid "Failed to create restore directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:2 +#, fuzzy +msgid "Failed to create temporary directory" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:3 +#, fuzzy +msgid "Failed to create temporary subdirectory" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:9 +#, fuzzy +msgid "Failed to create zip archive: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:27 +#, fuzzy +msgid "Failed to create zip entry: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:26 +#, fuzzy +msgid "Failed to create zip file: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:29 +#, fuzzy +msgid "Failed to create zip header: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:24 +#, fuzzy +msgid "Failed to decrypt data: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:49 +#, fuzzy +msgid "Failed to decrypt file: {0}" +msgstr "Devre dışı bırakılamadı %{msg}" + +#: src/constants/errors/backup.ts:35 +msgid "Failed to decrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:34 +msgid "Failed to decrypt Nginx UI directory: {0}" +msgstr "" + #: src/views/site/site_edit/RightSettings.vue:45 #: src/views/site/site_list/SiteList.vue:60 #: src/views/stream/components/RightSettings.vue:41 @@ -1095,23 +1266,109 @@ msgstr "Devre dışı bırakılamadı %{msg}" msgid "Failed to enable %{msg}" msgstr "Etkinleştirilemedi %{msg}" +#: src/constants/errors/backup.ts:23 +#, fuzzy +msgid "Failed to encrypt data: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:21 +#, fuzzy +msgid "Failed to encrypt file: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:8 +msgid "Failed to encrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:7 +msgid "Failed to encrypt Nginx UI directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:33 +#, fuzzy +msgid "Failed to extract archive: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:10 +#, fuzzy +msgid "Failed to generate AES key: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:11 +#, fuzzy +msgid "Failed to generate initialization vector: {0}" +msgstr "Sertifika bilgileri alınamadı" + #: src/language/constants.ts:5 msgid "Failed to get certificate information" msgstr "Sertifika bilgileri alınamadı" +#: src/constants/errors/backup.ts:28 +#, fuzzy +msgid "Failed to open source file: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:47 +#, fuzzy +msgid "Failed to open zip entry: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:43 +#, fuzzy +msgid "Failed to open zip file: {0}" +msgstr "Etkinleştirilemedi %{msg}" + #: src/constants/errors/self_check.ts:4 msgid "Failed to parse nginx.conf" msgstr "" +#: src/constants/errors/backup.ts:48 +msgid "Failed to read encrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:20 +#, fuzzy +msgid "Failed to read file: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:51 +msgid "Failed to read hash info file: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:3 msgid "Failed to read nginx.conf" msgstr "" +#: src/constants/errors/backup.ts:37 +msgid "Failed to restore Nginx configs: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:38 +msgid "Failed to restore Nginx UI files: {0}" +msgstr "" + #: src/views/site/site_edit/SiteEdit.vue:135 #: src/views/stream/StreamEdit.vue:122 msgid "Failed to save, syntax error(s) was detected in the configuration." msgstr "Kaydedilemedi, yapılandırmada sözdizimi hatası(ları) tespit edildi." +#: src/constants/errors/backup.ts:36 +#, fuzzy +msgid "Failed to verify hashes: {0}" +msgstr "Etkinleştirilemedi %{msg}" + +#: src/constants/errors/backup.ts:50 +msgid "Failed to write decrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:22 +msgid "Failed to write encrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:31 +msgid "Failed to write to zip buffer: {0}" +msgstr "" + #: src/language/constants.ts:32 msgid "File exists" msgstr "Dosya zaten var" @@ -1128,7 +1385,7 @@ msgstr "" msgid "Filter" msgstr "Filtre" -#: src/language/constants.ts:19 src/views/site/SiteAdd.vue:97 +#: src/language/constants.ts:19 src/views/site/site_add/SiteAdd.vue:97 msgid "Finished" msgstr "Bitmiş" @@ -1205,11 +1462,15 @@ msgstr "Sertifika alınıyor, lütfen bekleyin..." msgid "Github Proxy" msgstr "Github Proxy" +#: src/constants/errors/backup.ts:54 +msgid "Hash verification failed: file integrity compromised" +msgstr "" + #: src/components/SensitiveString/SensitiveString.vue:40 msgid "Hide" msgstr "Gizle" -#: src/routes/index.ts:30 +#: src/routes/index.ts:47 msgid "Home" msgstr "Anasayfa" @@ -1264,7 +1525,8 @@ msgstr "" msgid "Import" msgstr "İçe Aktar" -#: src/routes/index.ts:174 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:46 +#: src/views/certificate/CertificateEditor.vue:85 msgid "Import Certificate" msgstr "Sertifika İçe Aktar" @@ -1289,7 +1551,7 @@ msgstr "Uygulamadan kodu girin:" msgid "Input the recovery code:" msgstr "Kurtarma kodunu girin:" -#: src/routes/index.ts:312 src/views/other/Install.vue:134 +#: src/routes/modules/auth.ts:8 src/views/other/Install.vue:134 msgid "Install" msgstr "Yükle" @@ -1305,6 +1567,19 @@ msgstr "Aralık" msgid "Invalid" msgstr "Geçersiz" +#: src/constants/errors/backup.ts:42 +msgid "Invalid AES IV format: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:41 +msgid "Invalid AES key format: {0}" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:67 +#, fuzzy +msgid "Invalid file object" +msgstr "Geçersiz dosya adı" + #: src/views/config/components/Rename.vue:64 #: src/views/config/ConfigEditor.vue:250 msgid "Invalid filename" @@ -1319,6 +1594,10 @@ msgstr "Geçersiz klasör adı" msgid "Invalid otp code" msgstr "Geçersiz 2FA veya kurtarma kodu" +#: src/constants/errors/backup.ts:25 +msgid "Invalid padding in decrypted data" +msgstr "" + #: src/components/TwoFA/use2FAModal.ts:61 msgid "Invalid passcode or recovery code" msgstr "Geçersiz parola veya kurtarma kodu" @@ -1332,6 +1611,11 @@ msgstr "Geçersiz 2FA veya kurtarma kodu" msgid "Invalid request format" msgstr "" +#: src/constants/errors/backup.ts:40 +#, fuzzy +msgid "Invalid security token format" +msgstr "Geçersiz 2FA veya kurtarma kodu" + #: src/views/preference/AuthSettings.vue:18 msgid "IP" msgstr "IP" @@ -1447,7 +1731,7 @@ msgstr "Konumlar" msgid "Log" msgstr "Günlük" -#: src/routes/index.ts:318 src/views/other/Login.vue:222 +#: src/routes/modules/auth.ts:14 src/views/other/Login.vue:222 msgid "Login" msgstr "Giriş" @@ -1488,23 +1772,23 @@ msgstr "" "Sertifikayı almadan önce .well-known dizini için HTTPChallengePort'a bir " "ters proxy yapılandırdığınızdan emin olun." -#: src/routes/index.ts:108 src/views/config/ConfigEditor.vue:102 +#: src/routes/modules/config.ts:10 src/views/config/ConfigEditor.vue:102 #: src/views/config/ConfigEditor.vue:139 src/views/config/ConfigList.vue:69 #, fuzzy msgid "Manage Configs" msgstr "Yapılandırmaları Yönet" -#: src/routes/index.ts:47 src/views/site/site_list/SiteList.vue:94 +#: src/routes/modules/sites.ts:10 src/views/site/site_list/SiteList.vue:94 #, fuzzy msgid "Manage Sites" msgstr "Siteleri Yönet" -#: src/routes/index.ts:89 src/views/stream/StreamList.vue:119 +#: src/routes/modules/streams.ts:10 src/views/stream/StreamList.vue:119 #, fuzzy msgid "Manage Streams" msgstr "Akışları Yönet" -#: src/routes/index.ts:257 src/views/user/User.vue:10 +#: src/routes/modules/user.ts:10 src/views/user/User.vue:10 #, fuzzy msgid "Manage Users" msgstr "Kullanıcıları Yönet" @@ -1548,12 +1832,13 @@ msgstr "Model" msgid "Modify" msgstr "Değiştir" -#: src/routes/index.ts:164 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:36 +#: src/views/certificate/CertificateEditor.vue:85 #, fuzzy msgid "Modify Certificate" msgstr "Sertifika Değiştirme" -#: src/views/site/SiteAdd.vue:154 +#: src/views/site/site_add/SiteAdd.vue:154 #, fuzzy msgid "Modify Config" msgstr "Yapılandırmayı Değiştir" @@ -1625,7 +1910,7 @@ msgstr "Yeni sürüm yayınlandı" #: src/views/certificate/WildcardCertificate.vue:91 #: src/views/site/cert/components/ObtainCert.vue:211 -#: src/views/site/SiteAdd.vue:141 +#: src/views/site/site_add/SiteAdd.vue:141 #, fuzzy msgid "Next" msgstr "Sonraki" @@ -1664,6 +1949,16 @@ msgstr "" msgid "Nginx conf not include stream-enabled" msgstr "" +#: src/constants/errors/backup.ts:18 +#, fuzzy +msgid "Nginx config directory is not set" +msgstr "Nginx Yapılandırma Ayrıştırma Hatası" + +#: src/views/system/Backup/SystemRestore.vue:84 +#, fuzzy +msgid "Nginx configuration has been restored" +msgstr "Nginx Yapılandırma Ayrıştırma Hatası" + #: src/views/site/site_edit/SiteEdit.vue:223 #: src/views/stream/StreamEdit.vue:208 #, fuzzy @@ -1690,7 +1985,7 @@ msgstr "Nginx Hata Günlüğü Yolu" msgid "Nginx is not running" msgstr "Nginx çalışmıyor" -#: src/routes/index.ts:202 src/views/nginx_log/NginxLog.vue:148 +#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:148 #, fuzzy msgid "Nginx Log" msgstr "Nginx Günlüğü" @@ -1723,6 +2018,18 @@ msgstr "Terminal Başlatma Komutu" msgid "Nginx restarted successfully" msgstr "Nginx başarıyla yeniden başlatıldı" +#: src/views/system/Backup/SystemRestore.vue:88 +#, fuzzy +msgid "Nginx UI configuration has been restored" +msgstr "Nginx Yapılandırma Ayrıştırma Hatası" + +#: src/views/system/Backup/SystemRestore.vue:93 +#, fuzzy +msgid "" +"Nginx UI configuration has been restored and will restart automatically in a " +"few seconds." +msgstr "Nginx Yapılandırma Ayrıştırma Hatası" + #: src/components/ChatGPT/ChatGPT.vue:374 #: src/components/Notification/Notification.vue:133 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:63 @@ -1756,7 +2063,7 @@ msgstr "Düğüm Sırrı" msgid "Not After" msgstr "Sonra değil" -#: src/routes/index.ts:324 +#: src/routes/modules/error.ts:8 #, fuzzy msgid "Not Found" msgstr "Bulunamadı" @@ -1783,7 +2090,8 @@ msgstr "" msgid "Notification" msgstr "Bildirim" -#: src/components/Notification/Notification.vue:131 src/routes/index.ts:248 +#: src/components/Notification/Notification.vue:131 +#: src/routes/modules/notifications.ts:10 #, fuzzy msgid "Notifications" msgstr "Bildirimler" @@ -1840,6 +2148,8 @@ msgstr "Tamam" #: src/views/site/site_list/SiteList.vue:144 #: src/views/stream/components/RightSettings.vue:50 #: src/views/stream/StreamList.vue:164 +#: src/views/system/Backup/BackupCreator.vue:149 +#: src/views/system/Backup/SystemRestore.vue:94 #, fuzzy msgid "OK" msgstr "Tamam" @@ -1857,6 +2167,10 @@ msgstr "Doğrulama tamamlandıktan sonra kayıtlar kaldırılacaktır." msgid "Online" msgstr "Çevrimiçi" +#: src/views/system/Backup/SystemRestore.vue:24 +msgid "Only zip files are allowed" +msgstr "" + #: src/views/preference/Preference.vue:170 #, fuzzy msgid "OpenAI" @@ -1989,6 +2303,15 @@ msgstr "" msgid "Please enter the OTP code:" msgstr "Lütfen OTP kodunu girin:" +#: src/views/system/Backup/SystemRestore.vue:58 +#, fuzzy +msgid "Please enter the security token" +msgstr "Lütfen OTP kodunu girin:" + +#: src/views/system/Backup/SystemRestore.vue:153 +msgid "Please enter the security token received during backup" +msgstr "" + #: src/views/certificate/DNSCredential.vue:53 #, fuzzy msgid "" @@ -2070,6 +2393,15 @@ msgstr "" "Lütfen aşağıdaki zaman birimi konfigürasyonlarının tümünün saniye cinsinden " "olduğunu unutmayın." +#: src/views/system/Backup/BackupCreator.vue:107 +msgid "Please save this security token, you will need it for restoration:" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:53 +#, fuzzy +msgid "Please select a backup file" +msgstr "Lütfen en az bir düğüm seçin!" + #: src/views/environment/Environment.vue:58 #, fuzzy msgid "Please select at least one node to upgrade" @@ -2082,7 +2414,7 @@ msgstr "Lütfen yükseltmek için en az bir düğüm seçin" msgid "Pre-release" msgstr "Ön sürüm" -#: src/routes/index.ts:266 src/views/preference/Preference.vue:141 +#: src/routes/modules/preference.ts:10 src/views/preference/Preference.vue:141 #, fuzzy msgid "Preference" msgstr "Tercih" @@ -2399,6 +2731,21 @@ msgstr "Yeniden başlat" msgid "Restarting" msgstr "Yeniden Başlatma" +#: src/views/system/Backup/SystemRestore.vue:81 +#, fuzzy +msgid "Restore completed successfully" +msgstr "Başarıyla silindi" + +#: src/views/system/Backup/SystemRestore.vue:165 +#, fuzzy +msgid "Restore Nginx Configuration" +msgstr "Nginx Yapılandırma Ayrıştırma Hatası" + +#: src/views/system/Backup/SystemRestore.vue:176 +#, fuzzy +msgid "Restore Nginx UI Configuration" +msgstr "Nginx Yapılandırma Ayrıştırma Hatası" + #: src/views/preference/AuthSettings.vue:107 msgid "RP Display Name" msgstr "" @@ -2445,7 +2792,7 @@ msgstr "Direktifi Kaydet" #: src/views/config/ConfigEditor.vue:171 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:41 -#: src/views/site/SiteAdd.vue:46 +#: src/views/site/site_add/SiteAdd.vue:46 #, fuzzy msgid "Save error %{msg}" msgstr "Hatayı kaydet %{msg}" @@ -2501,7 +2848,8 @@ msgstr "Başarıyla kaydedin" #: src/views/config/ConfigEditor.vue:167 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:39 -#: src/views/site/site_edit/SiteEdit.vue:152 src/views/site/SiteAdd.vue:37 +#: src/views/site/site_add/SiteAdd.vue:37 +#: src/views/site/site_edit/SiteEdit.vue:152 #: src/views/stream/StreamEdit.vue:139 #, fuzzy msgid "Saved successfully" @@ -2522,12 +2870,21 @@ msgstr "SDK" msgid "Secret has been copied" msgstr "Sır kopyalandı" +#: src/views/system/Backup/SystemRestore.vue:150 +msgid "Security Token" +msgstr "" + +#: src/views/system/Backup/BackupCreator.vue:94 +#, fuzzy +msgid "Security Token Information" +msgstr "Geçersiz 2FA veya kurtarma kodu" + #: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:189 #, fuzzy msgid "Selector" msgstr "Selektör" -#: src/routes/index.ts:283 src/views/system/SelfCheck/SelfCheck.vue:42 +#: src/routes/modules/system.ts:19 src/views/system/SelfCheck/SelfCheck.vue:42 msgid "Self Check" msgstr "" @@ -2607,11 +2964,12 @@ msgstr "Bir geçiş anahtarı ile oturum açın" msgid "Single Directive" msgstr "Tek Direktif" -#: src/routes/index.ts:71 src/views/site/site_category/SiteCategory.vue:10 +#: src/routes/modules/sites.ts:34 +#: src/views/site/site_category/SiteCategory.vue:10 msgid "Site Categories" msgstr "" -#: src/views/site/SiteAdd.vue:147 +#: src/views/site/site_add/SiteAdd.vue:147 #, fuzzy msgid "Site Config Created Successfully" msgstr "Alan Adı Yapılandırması Başarıyla Oluşturuldu" @@ -2621,7 +2979,7 @@ msgstr "Alan Adı Yapılandırması Başarıyla Oluşturuldu" msgid "Site is enabled" msgstr "Devre dışı" -#: src/routes/index.ts:224 +#: src/routes/modules/nginx_log.ts:31 #, fuzzy msgid "Site Logs" msgstr "Site Günlükleri" @@ -2636,7 +2994,7 @@ msgstr "Dosya bulunamadı" msgid "Sites Directory" msgstr "Dizin" -#: src/routes/index.ts:56 +#: src/routes/modules/sites.ts:19 #, fuzzy msgid "Sites List" msgstr "Site Listesi" @@ -2681,6 +3039,10 @@ msgstr "SSO Girişi" msgid "Stable" msgstr "Stabil" +#: src/views/system/Backup/SystemRestore.vue:187 +msgid "Start Restore" +msgstr "" + #: src/views/certificate/ACMEUser.vue:65 #: src/views/certificate/CertificateList/certColumns.tsx:68 #: src/views/environment/envColumns.tsx:44 @@ -2737,6 +3099,10 @@ msgid "" "guide/nginx-proxy-example.html" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:140 +msgid "Supported file type: .zip" +msgstr "" + #: src/views/dashboard/ServerAnalytic.vue:236 #: src/views/dashboard/ServerAnalytic.vue:237 #, fuzzy @@ -2804,7 +3170,7 @@ msgstr "Senkronizasyon Yapılandırma Hatası" msgid "Sync Config Success" msgstr "Senkronizasyon Yapılandırması Başarılı" -#: src/views/site/site_category/SiteCategory.vue:17 +#: src/views/site/site_category/SiteCategory.vue:18 #, fuzzy msgid "Sync Nodes" msgstr "Şununla senkronize et" @@ -2824,22 +3190,32 @@ msgstr "Şununla senkronize et" msgid "Synchronization" msgstr "" -#: src/routes/index.ts:275 +#: src/routes/modules/system.ts:11 #, fuzzy msgid "System" msgstr "Sistem" +#: src/views/system/Backup/BackupCreator.vue:71 +#, fuzzy +msgid "System Backup" +msgstr "Sistem" + #: src/views/certificate/ACMEUserSelector.vue:88 #, fuzzy msgid "System Initial User" msgstr "Sistem İlk Kullanıcısı" +#: src/views/system/Backup/SystemRestore.vue:117 +#, fuzzy +msgid "System Restore" +msgstr "Sistem" + #: src/constants/errors/self_check.ts:2 #, fuzzy msgid "Task not found" msgstr "Dosya bulunamadı" -#: src/routes/index.ts:194 src/views/terminal/Terminal.vue:114 +#: src/routes/modules/terminal.ts:10 src/views/terminal/Terminal.vue:114 #, fuzzy msgid "Terminal" msgstr "terminal" @@ -2904,7 +3280,7 @@ msgid "" msgstr "" "Model adı yalnızca harf, unicode, sayı, tire, çizgi ve nokta içermelidir." -#: src/views/site/SiteAdd.vue:120 +#: src/views/site/site_add/SiteAdd.vue:120 #, fuzzy msgid "The parameter of server_name is required" msgstr "server_name parametresi gereklidir" @@ -3012,10 +3388,28 @@ msgid "" msgstr "" "Model adı yalnızca harf, unicode, sayı, tire, çizgi ve nokta içermelidir." +#: src/views/system/Backup/BackupCreator.vue:141 +msgid "" +"This token will only be shown once and cannot be retrieved later. Please " +"make sure to save it in a secure location." +msgstr "" + #: src/constants/form_errors.ts:4 msgid "This value is already taken" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:169 +msgid "" +"This will restore all Nginx configuration files. Nginx will restart after " +"the restoration is complete." +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:180 +msgid "" +"This will restore configuration files and database. Nginx UI will restart " +"after the restoration is complete." +msgstr "" + #: src/views/environment/BatchUpgrader.vue:182 #, fuzzy msgid "" @@ -3148,7 +3542,7 @@ msgstr "Güncelleme" msgid "Updated successfully" msgstr "Başarıyla güncellendi" -#: src/routes/index.ts:297 src/views/environment/Environment.vue:66 +#: src/routes/modules/system.ts:40 src/views/environment/Environment.vue:66 #: src/views/system/Upgrade.vue:143 src/views/system/Upgrade.vue:226 #, fuzzy msgid "Upgrade" @@ -3225,6 +3619,10 @@ msgstr "Kullanıcı adı (*)" msgid "Valid" msgstr "Geçerli" +#: src/views/system/Backup/SystemRestore.vue:159 +msgid "Verify Backup File Integrity" +msgstr "" + #: src/views/environment/envColumns.tsx:31 #, fuzzy msgid "Version" @@ -3264,11 +3662,19 @@ msgstr "Görünüm" #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33 #: src/views/notification/notificationColumns.tsx:22 #: src/views/preference/components/AddPasskey.vue:82 -#: src/views/site/SiteAdd.vue:115 +#: src/views/site/site_add/SiteAdd.vue:115 +#: src/views/system/Backup/BackupCreator.vue:138 #, fuzzy msgid "Warning" msgstr "Uyarı" +#: src/views/system/Backup/SystemRestore.vue:121 +msgid "" +"Warning: Restore operation will overwrite current configurations. Make sure " +"you have a valid backup file and security token, and carefully select what " +"to restore." +msgstr "" + #: src/views/certificate/DNSCredential.vue:56 #, fuzzy msgid "" @@ -3386,6 +3792,10 @@ msgstr "" msgid "Your passkeys" msgstr "Geçiş anahtarlarınız" +#, fuzzy +#~ msgid "Restart Required" +#~ msgstr "Yeniden Başlatma" + #~ msgid "Deploy %{conf_name} to %{node_name} successfully" #~ msgstr "" #~ "%{conf_name} yapılandırması başarıyla %{node_name} düğümüne dağıtıldı" @@ -3427,10 +3837,6 @@ msgstr "Geçiş anahtarlarınız" #~ msgid "Enable successfully" #~ msgstr "Başarıyla etkinleştirildi" -#, fuzzy -#~ msgid "Please select at least one node!" -#~ msgstr "Lütfen en az bir düğüm seçin!" - #, fuzzy #~ msgid "Please upgrade the remote Nginx UI to the latest version" #~ msgstr "" diff --git a/app/src/language/vi_VN/app.po b/app/src/language/vi_VN/app.po index d9f7fddf..fc304aea 100644 --- a/app/src/language/vi_VN/app.po +++ b/app/src/language/vi_VN/app.po @@ -17,15 +17,15 @@ msgstr "" msgid "2FA Settings" msgstr "" -#: src/routes/index.ts:290 +#: src/routes/modules/system.ts:26 msgid "About" msgstr "Tác giả" -#: src/routes/index.ts:210 src/views/site/ngx_conf/LogEntry.vue:75 +#: src/routes/modules/nginx_log.ts:17 src/views/site/ngx_conf/LogEntry.vue:75 msgid "Access Logs" msgstr "Log truy cập" -#: src/routes/index.ts:148 src/views/certificate/ACMEUser.vue:113 +#: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:113 #: src/views/certificate/ACMEUserSelector.vue:85 #, fuzzy msgid "ACME User" @@ -38,7 +38,7 @@ msgstr "Người dùng" #: src/views/environment/envColumns.tsx:97 #: src/views/notification/notificationColumns.tsx:65 #: src/views/preference/AuthSettings.vue:30 -#: src/views/site/site_category/columns.ts:29 +#: src/views/site/site_category/columns.ts:28 #: src/views/site/site_list/columns.tsx:76 src/views/stream/StreamList.vue:49 #: src/views/user/userColumns.tsx:60 msgid "Action" @@ -59,7 +59,7 @@ msgstr "Thêm" msgid "Add a passkey" msgstr "" -#: src/routes/index.ts:118 src/views/config/ConfigEditor.vue:144 +#: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:144 #: src/views/config/ConfigEditor.vue:204 #, fuzzy msgid "Add Configuration" @@ -74,7 +74,7 @@ msgstr "Thêm Directive" msgid "Add Location" msgstr "Thêm Location" -#: src/routes/index.ts:63 src/views/site/SiteAdd.vue:89 +#: src/routes/modules/sites.ts:26 src/views/site/site_add/SiteAdd.vue:89 msgid "Add Site" msgstr "Thêm Website" @@ -263,6 +263,10 @@ msgstr "Đã tắt tự động gia hạn SSL cho %{name}" msgid "Auto-renewal enabled for %{name}" msgstr "Đã bật tự động gia hạn SSL cho %{name}" +#: src/views/system/Backup/SystemRestore.vue:92 +msgid "Automatic Restart" +msgstr "" + #: src/views/certificate/CertificateEditor.vue:255 #: src/views/config/ConfigEditor.vue:213 src/views/config/ConfigList.vue:106 #: src/views/config/ConfigList.vue:180 src/views/nginx_log/NginxLog.vue:173 @@ -280,6 +284,25 @@ msgstr "Quay lại" msgid "Back to list" msgstr "" +#: src/routes/modules/system.ts:33 +#, fuzzy +msgid "Backup" +msgstr "Quay lại" + +#: src/views/system/Backup/SystemRestore.vue:100 +msgid "Backup file integrity check failed, it may have been tampered with" +msgstr "" + +#: src/constants/errors/backup.ts:39 +#, fuzzy +msgid "Backup file not found: {0}" +msgstr "Không tìm thấy tệp tin" + +#: src/views/system/Backup/BackupCreator.vue:42 +#, fuzzy +msgid "Backup has been downloaded successfully" +msgstr "Reload Nginx thành công" + #: src/views/preference/AuthSettings.vue:129 msgid "Ban Threshold Minutes" msgstr "" @@ -292,7 +315,7 @@ msgstr "" msgid "Banned Until" msgstr "" -#: src/views/site/SiteAdd.vue:95 +#: src/views/site/site_add/SiteAdd.vue:95 msgid "Base information" msgstr "Thông tin" @@ -410,13 +433,13 @@ msgid_plural "Certificates Status" msgstr[0] "Trạng thái chứng chỉ" msgstr[1] "Trạng thái chứng chỉ" -#: src/routes/index.ts:139 +#: src/routes/modules/certificates.ts:11 #: src/views/certificate/CertificateList/Certificate.vue:13 #, fuzzy msgid "Certificates" msgstr "Chứng chỉ" -#: src/routes/index.ts:156 +#: src/routes/modules/certificates.ts:28 #, fuzzy msgid "Certificates List" msgstr "Danh sách chứng chỉ" @@ -491,6 +514,10 @@ msgstr "Xoá" msgid "Cleared successfully" msgstr "Đã xóa thành công" +#: src/views/system/Backup/SystemRestore.vue:137 +msgid "Click or drag backup file to this area to upload" +msgstr "" + #: src/views/preference/components/TOTP.vue:110 msgid "Click to copy" msgstr "" @@ -507,6 +534,11 @@ msgstr "Bình luận" msgid "Comments" msgstr "Bình luận" +#: src/constants/errors/backup.ts:13 +#, fuzzy +msgid "Config path is empty" +msgstr "Mẫu Cấu hình" + #: src/views/site/ngx_conf/config_template/ConfigTemplate.vue:84 #, fuzzy msgid "Config Templates" @@ -516,7 +548,7 @@ msgstr "Mẫu Cấu hình" msgid "Configuration file is test successful" msgstr "Tệp cấu hình được kiểm tra thành công" -#: src/views/site/SiteAdd.vue:101 +#: src/views/site/site_add/SiteAdd.vue:101 msgid "Configuration Name" msgstr "Tên cấu hình" @@ -524,7 +556,7 @@ msgstr "Tên cấu hình" msgid "Configurations" msgstr "Cấu hình" -#: src/views/site/SiteAdd.vue:96 +#: src/views/site/site_add/SiteAdd.vue:96 msgid "Configure SSL" msgstr "Cấu hình SSL" @@ -548,7 +580,12 @@ msgstr "Nội dung" msgid "Copied" msgstr "" +#: src/views/system/Backup/BackupCreator.vue:128 +msgid "Copied!" +msgstr "" + #: src/components/SensitiveString/SensitiveString.vue:37 +#: src/views/system/Backup/BackupCreator.vue:128 msgid "Copy" msgstr "" @@ -573,10 +610,15 @@ msgstr "CPU:" msgid "Create" msgstr "Ngày tạo" -#: src/views/site/SiteAdd.vue:157 +#: src/views/site/site_add/SiteAdd.vue:157 msgid "Create Another" msgstr "Tạo thêm" +#: src/views/system/Backup/BackupCreator.vue:86 +#, fuzzy +msgid "Create Backup" +msgstr "Ngày tạo" + #: src/views/config/ConfigList.vue:116 #, fuzzy msgid "Create File" @@ -587,9 +629,15 @@ msgstr "Ngày tạo" msgid "Create Folder" msgstr "Tạo thêm" +#: src/views/system/Backup/BackupCreator.vue:75 +msgid "" +"Create system backups including Nginx configuration and Nginx UI settings. " +"Backup files will be automatically downloaded to your computer." +msgstr "" + #: src/views/notification/notificationColumns.tsx:58 #: src/views/preference/components/Passkey.vue:95 -#: src/views/site/site_category/columns.ts:15 src/views/user/userColumns.tsx:48 +#: src/views/site/site_category/columns.ts:16 src/views/user/userColumns.tsx:48 msgid "Created at" msgstr "Ngày tạo" @@ -633,7 +681,7 @@ msgid "" "indicator." msgstr "" -#: src/routes/index.ts:38 src/views/config/ConfigEditor.vue:134 +#: src/routes/modules/dashboard.ts:10 src/views/config/ConfigEditor.vue:134 #: src/views/config/ConfigEditor.vue:97 src/views/config/ConfigList.vue:64 msgid "Dashboard" msgstr "Bảng điều khiển" @@ -830,7 +878,8 @@ msgstr "Đã tắt thành công" msgid "Disk IO" msgstr "Disk IO" -#: src/routes/index.ts:184 src/views/certificate/DNSCredential.vue:40 +#: src/routes/modules/certificates.ts:56 +#: src/views/certificate/DNSCredential.vue:40 msgid "DNS Credentials" msgstr "Xác thực DNS" @@ -945,15 +994,15 @@ msgstr "Sửa %{n}" msgid "Edit %{n}" msgstr "Sửa %{n}" -#: src/routes/index.ts:128 src/views/config/ConfigEditor.vue:204 +#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:204 msgid "Edit Configuration" msgstr "Sửa cấu hình" -#: src/routes/index.ts:78 +#: src/routes/modules/sites.ts:41 msgid "Edit Site" msgstr "Sửa trang web" -#: src/routes/index.ts:98 +#: src/routes/modules/streams.ts:19 #, fuzzy msgid "Edit Stream" msgstr "Sửa trang web" @@ -982,7 +1031,7 @@ msgstr "Đã bật" msgid "Enable auto-renewal failed for %{name}" msgstr "Không thể bật tự động gia hạn SSL cho %{name}" -#: src/views/site/SiteAdd.vue:43 +#: src/views/site/site_add/SiteAdd.vue:43 msgid "Enable failed" msgstr "Bật không thành công" @@ -1048,8 +1097,9 @@ msgstr "Bật TLS" msgid "Enabled" msgstr "Đã bật" +#: src/views/site/site_add/SiteAdd.vue:40 #: src/views/site/site_edit/RightSettings.vue:33 -#: src/views/site/site_list/SiteList.vue:46 src/views/site/SiteAdd.vue:40 +#: src/views/site/site_list/SiteList.vue:46 #: src/views/stream/components/RightSettings.vue:29 #: src/views/stream/StreamList.vue:61 msgid "Enabled successfully" @@ -1064,7 +1114,8 @@ msgstr "Bảo mật trang web với Let's Encrypt" msgid "Environment variables cleaned" msgstr "Đặt biến môi trường" -#: src/routes/index.ts:234 src/views/dashboard/Environments.vue:83 +#: src/routes/modules/environments.ts:11 +#: src/views/dashboard/Environments.vue:83 #: src/views/environment/Environment.vue:43 #, fuzzy msgid "Environments" @@ -1075,7 +1126,7 @@ msgstr "Environments" msgid "Error" msgstr "Lỗi" -#: src/routes/index.ts:217 src/views/site/ngx_conf/LogEntry.vue:83 +#: src/routes/modules/nginx_log.ts:24 src/views/site/ngx_conf/LogEntry.vue:83 msgid "Error Logs" msgstr "Log lỗi" @@ -1102,11 +1153,130 @@ msgstr "Xuất" msgid "Fail to obtain certificate" msgstr "Nhận chứng chỉ" +#: src/constants/errors/backup.ts:5 +msgid "Failed to backup Nginx config files: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:4 +msgid "Failed to backup Nginx UI files: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:17 +#, fuzzy +msgid "Failed to calculate hash: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:53 +msgid "Failed to calculate Nginx hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:52 +msgid "Failed to calculate Nginx UI hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:14 +msgid "Failed to copy config file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:15 +msgid "Failed to copy database directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:16 +#, fuzzy +msgid "Failed to copy database file: {0}" +msgstr "Không thể tắt %{msg}" + +#: src/constants/errors/backup.ts:30 +msgid "Failed to copy file content: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:19 +msgid "Failed to copy Nginx config directory: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:9 #, fuzzy msgid "Failed to create backup" msgstr "Không thể bật %{msg}" +#: src/constants/errors/backup.ts:12 +#, fuzzy +msgid "Failed to create backup file: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:44 +#, fuzzy +msgid "Failed to create directory: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:46 +#, fuzzy +msgid "Failed to create file: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:6 +#, fuzzy +msgid "Failed to create hash info file: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:45 +#, fuzzy +msgid "Failed to create parent directory: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:32 +msgid "Failed to create restore directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:2 +#, fuzzy +msgid "Failed to create temporary directory" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:3 +#, fuzzy +msgid "Failed to create temporary subdirectory" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:9 +#, fuzzy +msgid "Failed to create zip archive: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:27 +#, fuzzy +msgid "Failed to create zip entry: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:26 +#, fuzzy +msgid "Failed to create zip file: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:29 +#, fuzzy +msgid "Failed to create zip header: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:24 +#, fuzzy +msgid "Failed to decrypt data: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:49 +#, fuzzy +msgid "Failed to decrypt file: {0}" +msgstr "Không thể tắt %{msg}" + +#: src/constants/errors/backup.ts:35 +msgid "Failed to decrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:34 +msgid "Failed to decrypt Nginx UI directory: {0}" +msgstr "" + #: src/views/site/site_edit/RightSettings.vue:45 #: src/views/site/site_list/SiteList.vue:60 #: src/views/stream/components/RightSettings.vue:41 @@ -1121,23 +1291,109 @@ msgstr "Không thể tắt %{msg}" msgid "Failed to enable %{msg}" msgstr "Không thể bật %{msg}" +#: src/constants/errors/backup.ts:23 +#, fuzzy +msgid "Failed to encrypt data: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:21 +#, fuzzy +msgid "Failed to encrypt file: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:8 +msgid "Failed to encrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:7 +msgid "Failed to encrypt Nginx UI directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:33 +#, fuzzy +msgid "Failed to extract archive: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:10 +#, fuzzy +msgid "Failed to generate AES key: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:11 +#, fuzzy +msgid "Failed to generate initialization vector: {0}" +msgstr "Không thể truy xuất thông tin chứng chỉ" + #: src/language/constants.ts:5 msgid "Failed to get certificate information" msgstr "Không thể truy xuất thông tin chứng chỉ" +#: src/constants/errors/backup.ts:28 +#, fuzzy +msgid "Failed to open source file: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:47 +#, fuzzy +msgid "Failed to open zip entry: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:43 +#, fuzzy +msgid "Failed to open zip file: {0}" +msgstr "Không thể bật %{msg}" + #: src/constants/errors/self_check.ts:4 msgid "Failed to parse nginx.conf" msgstr "" +#: src/constants/errors/backup.ts:48 +msgid "Failed to read encrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:20 +#, fuzzy +msgid "Failed to read file: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:51 +msgid "Failed to read hash info file: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:3 msgid "Failed to read nginx.conf" msgstr "" +#: src/constants/errors/backup.ts:37 +msgid "Failed to restore Nginx configs: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:38 +msgid "Failed to restore Nginx UI files: {0}" +msgstr "" + #: src/views/site/site_edit/SiteEdit.vue:135 #: src/views/stream/StreamEdit.vue:122 msgid "Failed to save, syntax error(s) was detected in the configuration." msgstr "Không lưu được, đã phát hiện thấy (các) lỗi cú pháp trong cấu hình." +#: src/constants/errors/backup.ts:36 +#, fuzzy +msgid "Failed to verify hashes: {0}" +msgstr "Không thể bật %{msg}" + +#: src/constants/errors/backup.ts:50 +msgid "Failed to write decrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:22 +msgid "Failed to write encrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:31 +msgid "Failed to write to zip buffer: {0}" +msgstr "" + #: src/language/constants.ts:32 msgid "File exists" msgstr "Tệp tin đã tồn tại" @@ -1154,7 +1410,7 @@ msgstr "" msgid "Filter" msgstr "Lọc" -#: src/language/constants.ts:19 src/views/site/SiteAdd.vue:97 +#: src/language/constants.ts:19 src/views/site/site_add/SiteAdd.vue:97 msgid "Finished" msgstr "Đã hoàn thành" @@ -1232,11 +1488,15 @@ msgstr "Đang lấy chứng chỉ, vui lòng đợi..." msgid "Github Proxy" msgstr "" +#: src/constants/errors/backup.ts:54 +msgid "Hash verification failed: file integrity compromised" +msgstr "" + #: src/components/SensitiveString/SensitiveString.vue:40 msgid "Hide" msgstr "" -#: src/routes/index.ts:30 +#: src/routes/index.ts:47 msgid "Home" msgstr "Trang chủ" @@ -1285,7 +1545,8 @@ msgstr "" msgid "Import" msgstr "Xuất" -#: src/routes/index.ts:174 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:46 +#: src/views/certificate/CertificateEditor.vue:85 #, fuzzy msgid "Import Certificate" msgstr "Chứng chỉ" @@ -1311,7 +1572,7 @@ msgstr "" msgid "Input the recovery code:" msgstr "" -#: src/routes/index.ts:312 src/views/other/Install.vue:134 +#: src/routes/modules/auth.ts:8 src/views/other/Install.vue:134 msgid "Install" msgstr "Cài đặt" @@ -1329,6 +1590,19 @@ msgstr "" msgid "Invalid" msgstr "Hợp lệ" +#: src/constants/errors/backup.ts:42 +msgid "Invalid AES IV format: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:41 +msgid "Invalid AES key format: {0}" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:67 +#, fuzzy +msgid "Invalid file object" +msgstr "E-mail không chính xác!" + #: src/views/config/components/Rename.vue:64 #: src/views/config/ConfigEditor.vue:250 #, fuzzy @@ -1344,6 +1618,10 @@ msgstr "" msgid "Invalid otp code" msgstr "Hợp lệ" +#: src/constants/errors/backup.ts:25 +msgid "Invalid padding in decrypted data" +msgstr "" + #: src/components/TwoFA/use2FAModal.ts:61 msgid "Invalid passcode or recovery code" msgstr "" @@ -1356,6 +1634,10 @@ msgstr "" msgid "Invalid request format" msgstr "" +#: src/constants/errors/backup.ts:40 +msgid "Invalid security token format" +msgstr "" + #: src/views/preference/AuthSettings.vue:18 msgid "IP" msgstr "" @@ -1483,7 +1765,7 @@ msgstr "Locations" msgid "Log" msgstr "Log" -#: src/routes/index.ts:318 src/views/other/Login.vue:222 +#: src/routes/modules/auth.ts:14 src/views/other/Login.vue:222 msgid "Login" msgstr "Đăng nhập" @@ -1518,21 +1800,21 @@ msgstr "" "Đảm bảo rằng bạn đã định cấu hình proxy ngược (reverse proxy) thư mục .well-" "known tới HTTPChallengePort (default: 9180) trước khi ký chứng chỉ SSL." -#: src/routes/index.ts:108 src/views/config/ConfigEditor.vue:102 +#: src/routes/modules/config.ts:10 src/views/config/ConfigEditor.vue:102 #: src/views/config/ConfigEditor.vue:139 src/views/config/ConfigList.vue:69 msgid "Manage Configs" msgstr "Quản lý cấu hình" -#: src/routes/index.ts:47 src/views/site/site_list/SiteList.vue:94 +#: src/routes/modules/sites.ts:10 src/views/site/site_list/SiteList.vue:94 msgid "Manage Sites" msgstr "Quản lý Website" -#: src/routes/index.ts:89 src/views/stream/StreamList.vue:119 +#: src/routes/modules/streams.ts:10 src/views/stream/StreamList.vue:119 #, fuzzy msgid "Manage Streams" msgstr "Quản lý Website" -#: src/routes/index.ts:257 src/views/user/User.vue:10 +#: src/routes/modules/user.ts:10 src/views/user/User.vue:10 msgid "Manage Users" msgstr "Người dùng" @@ -1570,12 +1852,13 @@ msgstr "Run Mode" msgid "Modify" msgstr "Sửa" -#: src/routes/index.ts:164 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:36 +#: src/views/certificate/CertificateEditor.vue:85 #, fuzzy msgid "Modify Certificate" msgstr "Sửa chứng chỉ" -#: src/views/site/SiteAdd.vue:154 +#: src/views/site/site_add/SiteAdd.vue:154 msgid "Modify Config" msgstr "Sửa cấu hình" @@ -1640,7 +1923,7 @@ msgstr "Đã có phiên bản mới" #: src/views/certificate/WildcardCertificate.vue:91 #: src/views/site/cert/components/ObtainCert.vue:211 -#: src/views/site/SiteAdd.vue:141 +#: src/views/site/site_add/SiteAdd.vue:141 msgid "Next" msgstr "Tiếp theo" @@ -1676,6 +1959,16 @@ msgstr "" msgid "Nginx conf not include stream-enabled" msgstr "" +#: src/constants/errors/backup.ts:18 +#, fuzzy +msgid "Nginx config directory is not set" +msgstr "Lỗi phân tích cú pháp cấu hình Nginx" + +#: src/views/system/Backup/SystemRestore.vue:84 +#, fuzzy +msgid "Nginx configuration has been restored" +msgstr "Lỗi phân tích cú pháp cấu hình Nginx" + #: src/views/site/site_edit/SiteEdit.vue:223 #: src/views/stream/StreamEdit.vue:208 #, fuzzy @@ -1699,7 +1992,7 @@ msgstr "Vị trí lưu log lỗi (Error log) của Nginx" msgid "Nginx is not running" msgstr "" -#: src/routes/index.ts:202 src/views/nginx_log/NginxLog.vue:148 +#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:148 msgid "Nginx Log" msgstr "" @@ -1730,6 +2023,18 @@ msgstr "" msgid "Nginx restarted successfully" msgstr "Restart Nginx thành công" +#: src/views/system/Backup/SystemRestore.vue:88 +#, fuzzy +msgid "Nginx UI configuration has been restored" +msgstr "Lỗi phân tích cú pháp cấu hình Nginx" + +#: src/views/system/Backup/SystemRestore.vue:93 +#, fuzzy +msgid "" +"Nginx UI configuration has been restored and will restart automatically in a " +"few seconds." +msgstr "Lỗi phân tích cú pháp cấu hình Nginx" + #: src/components/ChatGPT/ChatGPT.vue:374 #: src/components/Notification/Notification.vue:133 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:63 @@ -1760,7 +2065,7 @@ msgstr "" msgid "Not After" msgstr "Không phải sau khi" -#: src/routes/index.ts:324 +#: src/routes/modules/error.ts:8 msgid "Not Found" msgstr "Không tìm thấy" @@ -1784,7 +2089,8 @@ msgstr "" msgid "Notification" msgstr "Thông báo" -#: src/components/Notification/Notification.vue:131 src/routes/index.ts:248 +#: src/components/Notification/Notification.vue:131 +#: src/routes/modules/notifications.ts:10 #, fuzzy msgid "Notifications" msgstr "Thông báo" @@ -1834,6 +2140,8 @@ msgstr "" #: src/views/site/site_list/SiteList.vue:144 #: src/views/stream/components/RightSettings.vue:50 #: src/views/stream/StreamList.vue:164 +#: src/views/system/Backup/BackupCreator.vue:149 +#: src/views/system/Backup/SystemRestore.vue:94 msgid "OK" msgstr "" @@ -1848,6 +2156,10 @@ msgstr "Sau khi quá trình xác minh hoàn tất, bản ghi sẽ bị xóa." msgid "Online" msgstr "Trực tuyến" +#: src/views/system/Backup/SystemRestore.vue:24 +msgid "Only zip files are allowed" +msgstr "" + #: src/views/preference/Preference.vue:170 msgid "OpenAI" msgstr "" @@ -1957,6 +2269,14 @@ msgstr "" msgid "Please enter the OTP code:" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:58 +msgid "Please enter the security token" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:153 +msgid "Please enter the security token received during backup" +msgstr "" + #: src/views/certificate/DNSCredential.vue:53 msgid "" "Please fill in the API authentication credentials provided by your DNS " @@ -2026,6 +2346,15 @@ msgid "" "Please note that the unit of time configurations below are all in seconds." msgstr "Lưu ý đơn vị cấu hình thời gian bên dưới được tính bằng giây." +#: src/views/system/Backup/BackupCreator.vue:107 +msgid "Please save this security token, you will need it for restoration:" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:53 +#, fuzzy +msgid "Please select a backup file" +msgstr "Vui lòng nhập username!" + #: src/views/environment/Environment.vue:58 msgid "Please select at least one node to upgrade" msgstr "" @@ -2036,7 +2365,7 @@ msgstr "" msgid "Pre-release" msgstr "" -#: src/routes/index.ts:266 src/views/preference/Preference.vue:141 +#: src/routes/modules/preference.ts:10 src/views/preference/Preference.vue:141 msgid "Preference" msgstr "Cài đặt" @@ -2321,6 +2650,21 @@ msgstr "Khởi động lại" msgid "Restarting" msgstr "Đang khởi động lại" +#: src/views/system/Backup/SystemRestore.vue:81 +#, fuzzy +msgid "Restore completed successfully" +msgstr "Đã xoá thành công" + +#: src/views/system/Backup/SystemRestore.vue:165 +#, fuzzy +msgid "Restore Nginx Configuration" +msgstr "Lỗi phân tích cú pháp cấu hình Nginx" + +#: src/views/system/Backup/SystemRestore.vue:176 +#, fuzzy +msgid "Restore Nginx UI Configuration" +msgstr "Lỗi phân tích cú pháp cấu hình Nginx" + #: src/views/preference/AuthSettings.vue:107 msgid "RP Display Name" msgstr "" @@ -2364,7 +2708,7 @@ msgstr "Lưu Directive" #: src/views/config/ConfigEditor.vue:171 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:41 -#: src/views/site/SiteAdd.vue:46 +#: src/views/site/site_add/SiteAdd.vue:46 msgid "Save error %{msg}" msgstr "Đã xảy ra lỗi khi lưu %{msg}" @@ -2418,7 +2762,8 @@ msgstr "Lưu thành công" #: src/views/config/ConfigEditor.vue:167 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:39 -#: src/views/site/site_edit/SiteEdit.vue:152 src/views/site/SiteAdd.vue:37 +#: src/views/site/site_add/SiteAdd.vue:37 +#: src/views/site/site_edit/SiteEdit.vue:152 #: src/views/stream/StreamEdit.vue:139 msgid "Saved successfully" msgstr "Lưu thành công" @@ -2435,11 +2780,19 @@ msgstr "" msgid "Secret has been copied" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:150 +msgid "Security Token" +msgstr "" + +#: src/views/system/Backup/BackupCreator.vue:94 +msgid "Security Token Information" +msgstr "" + #: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:189 msgid "Selector" msgstr "Bộ chọn" -#: src/routes/index.ts:283 src/views/system/SelfCheck/SelfCheck.vue:42 +#: src/routes/modules/system.ts:19 src/views/system/SelfCheck/SelfCheck.vue:42 msgid "Self Check" msgstr "" @@ -2508,11 +2861,12 @@ msgstr "" msgid "Single Directive" msgstr "Single Directive" -#: src/routes/index.ts:71 src/views/site/site_category/SiteCategory.vue:10 +#: src/routes/modules/sites.ts:34 +#: src/views/site/site_category/SiteCategory.vue:10 msgid "Site Categories" msgstr "" -#: src/views/site/SiteAdd.vue:147 +#: src/views/site/site_add/SiteAdd.vue:147 #, fuzzy msgid "Site Config Created Successfully" msgstr "Tên miền đã được tạo" @@ -2522,7 +2876,7 @@ msgstr "Tên miền đã được tạo" msgid "Site is enabled" msgstr "Đã tắt" -#: src/routes/index.ts:224 +#: src/routes/modules/nginx_log.ts:31 #, fuzzy msgid "Site Logs" msgstr "Logs" @@ -2537,7 +2891,7 @@ msgstr "Không tìm thấy tệp tin" msgid "Sites Directory" msgstr "Thư mục" -#: src/routes/index.ts:56 +#: src/routes/modules/sites.ts:19 msgid "Sites List" msgstr "Danh sách Website" @@ -2576,6 +2930,10 @@ msgstr "" msgid "Stable" msgstr "Ổn định" +#: src/views/system/Backup/SystemRestore.vue:187 +msgid "Start Restore" +msgstr "" + #: src/views/certificate/ACMEUser.vue:65 #: src/views/certificate/CertificateList/certColumns.tsx:68 #: src/views/environment/envColumns.tsx:44 @@ -2628,6 +2986,10 @@ msgid "" "guide/nginx-proxy-example.html" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:140 +msgid "Supported file type: .zip" +msgstr "" + #: src/views/dashboard/ServerAnalytic.vue:236 #: src/views/dashboard/ServerAnalytic.vue:237 msgid "Swap" @@ -2691,7 +3053,7 @@ msgstr "Gia hạn chứng chỉ SSL thất bại" msgid "Sync Config Success" msgstr "Gia hạn chứng chỉ SSL thành công" -#: src/views/site/site_category/SiteCategory.vue:17 +#: src/views/site/site_category/SiteCategory.vue:18 msgid "Sync Nodes" msgstr "" @@ -2709,20 +3071,30 @@ msgstr "" msgid "Synchronization" msgstr "" -#: src/routes/index.ts:275 +#: src/routes/modules/system.ts:11 msgid "System" msgstr "Thông tin" +#: src/views/system/Backup/BackupCreator.vue:71 +#, fuzzy +msgid "System Backup" +msgstr "Thông tin" + #: src/views/certificate/ACMEUserSelector.vue:88 msgid "System Initial User" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:117 +#, fuzzy +msgid "System Restore" +msgstr "Thông tin" + #: src/constants/errors/self_check.ts:2 #, fuzzy msgid "Task not found" msgstr "Không tìm thấy tệp tin" -#: src/routes/index.ts:194 src/views/terminal/Terminal.vue:114 +#: src/routes/modules/terminal.ts:10 src/views/terminal/Terminal.vue:114 msgid "Terminal" msgstr "Terminal" @@ -2775,7 +3147,7 @@ msgid "" "dashes, colons, and dots." msgstr "" -#: src/views/site/SiteAdd.vue:120 +#: src/views/site/site_add/SiteAdd.vue:120 #, fuzzy msgid "The parameter of server_name is required" msgstr "Tham số server_name là bắt buộc" @@ -2864,10 +3236,28 @@ msgid "" "This field should only contain letters, unicode characters, numbers, and -_." msgstr "" +#: src/views/system/Backup/BackupCreator.vue:141 +msgid "" +"This token will only be shown once and cannot be retrieved later. Please " +"make sure to save it in a secure location." +msgstr "" + #: src/constants/form_errors.ts:4 msgid "This value is already taken" msgstr "" +#: src/views/system/Backup/SystemRestore.vue:169 +msgid "" +"This will restore all Nginx configuration files. Nginx will restart after " +"the restoration is complete." +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:180 +msgid "" +"This will restore configuration files and database. Nginx UI will restart " +"after the restoration is complete." +msgstr "" + #: src/views/environment/BatchUpgrader.vue:182 msgid "" "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}." @@ -2974,7 +3364,7 @@ msgstr "Ngày cập nhật" msgid "Updated successfully" msgstr "Cập nhật thành công" -#: src/routes/index.ts:297 src/views/environment/Environment.vue:66 +#: src/routes/modules/system.ts:40 src/views/environment/Environment.vue:66 #: src/views/system/Upgrade.vue:143 src/views/system/Upgrade.vue:226 msgid "Upgrade" msgstr "Cập nhật" @@ -3041,6 +3431,10 @@ msgstr "Username (*)" msgid "Valid" msgstr "Hợp lệ" +#: src/views/system/Backup/SystemRestore.vue:159 +msgid "Verify Backup File Integrity" +msgstr "" + #: src/views/environment/envColumns.tsx:31 #, fuzzy msgid "Version" @@ -3078,10 +3472,18 @@ msgstr "Xem" #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33 #: src/views/notification/notificationColumns.tsx:22 #: src/views/preference/components/AddPasskey.vue:82 -#: src/views/site/SiteAdd.vue:115 +#: src/views/site/site_add/SiteAdd.vue:115 +#: src/views/system/Backup/BackupCreator.vue:138 msgid "Warning" msgstr "Lưu ý" +#: src/views/system/Backup/SystemRestore.vue:121 +msgid "" +"Warning: Restore operation will overwrite current configurations. Make sure " +"you have a valid backup file and security token, and carefully select what " +"to restore." +msgstr "" + #: src/views/certificate/DNSCredential.vue:56 msgid "" "We will add one or more TXT records to the DNS records of your domain for " @@ -3183,6 +3585,10 @@ msgstr "" msgid "Your passkeys" msgstr "" +#, fuzzy +#~ msgid "Restart Required" +#~ msgstr "Đang khởi động lại" + #~ msgid "Deploy %{conf_name} to %{node_name} successfully" #~ msgstr "Triển khai %{conf_name} tới %{node_name} thành công" diff --git a/app/src/language/zh_CN/app.po b/app/src/language/zh_CN/app.po index 7bec330f..852521c9 100644 --- a/app/src/language/zh_CN/app.po +++ b/app/src/language/zh_CN/app.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2025-03-03 17:51+0800\n" +"PO-Revision-Date: 2025-03-29 18:45+0800\n" "Last-Translator: 0xJacky \n" "Language-Team: Chinese (Simplified Han script) \n" @@ -23,15 +23,15 @@ msgstr "2FA" msgid "2FA Settings" msgstr "2FA 设置" -#: src/routes/index.ts:290 +#: src/routes/modules/system.ts:26 msgid "About" msgstr "关于" -#: src/routes/index.ts:210 src/views/site/ngx_conf/LogEntry.vue:75 +#: src/routes/modules/nginx_log.ts:17 src/views/site/ngx_conf/LogEntry.vue:75 msgid "Access Logs" msgstr "访问日志" -#: src/routes/index.ts:148 src/views/certificate/ACMEUser.vue:113 +#: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:113 #: src/views/certificate/ACMEUserSelector.vue:85 msgid "ACME User" msgstr "ACME 用户" @@ -43,7 +43,7 @@ msgstr "ACME 用户" #: src/views/environment/envColumns.tsx:97 #: src/views/notification/notificationColumns.tsx:65 #: src/views/preference/AuthSettings.vue:30 -#: src/views/site/site_category/columns.ts:29 +#: src/views/site/site_category/columns.ts:28 #: src/views/site/site_list/columns.tsx:76 src/views/stream/StreamList.vue:49 #: src/views/user/userColumns.tsx:60 msgid "Action" @@ -64,7 +64,7 @@ msgstr "添加" msgid "Add a passkey" msgstr "添加 Passkey" -#: src/routes/index.ts:118 src/views/config/ConfigEditor.vue:144 +#: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:144 #: src/views/config/ConfigEditor.vue:204 msgid "Add Configuration" msgstr "添加配置" @@ -78,7 +78,7 @@ msgstr "在下面添加指令" msgid "Add Location" msgstr "添加 Location" -#: src/routes/index.ts:63 src/views/site/SiteAdd.vue:89 +#: src/routes/modules/sites.ts:26 src/views/site/site_add/SiteAdd.vue:89 msgid "Add Site" msgstr "添加站点" @@ -248,6 +248,10 @@ msgstr "成功关闭 %{name} 自动续签" msgid "Auto-renewal enabled for %{name}" msgstr "成功启用 %{name} 自动续签" +#: src/views/system/Backup/SystemRestore.vue:92 +msgid "Automatic Restart" +msgstr "自动重启" + #: src/views/certificate/CertificateEditor.vue:255 #: src/views/config/ConfigEditor.vue:213 src/views/config/ConfigList.vue:106 #: src/views/config/ConfigList.vue:180 src/views/nginx_log/NginxLog.vue:173 @@ -264,6 +268,22 @@ msgstr "返回首页" msgid "Back to list" msgstr "返回列表" +#: src/routes/modules/system.ts:33 +msgid "Backup" +msgstr "备份" + +#: src/views/system/Backup/SystemRestore.vue:100 +msgid "Backup file integrity check failed, it may have been tampered with" +msgstr "备份文件完整性检查失败,可能已被篡改" + +#: src/constants/errors/backup.ts:39 +msgid "Backup file not found: {0}" +msgstr "未找到备份文件:{0}" + +#: src/views/system/Backup/BackupCreator.vue:42 +msgid "Backup has been downloaded successfully" +msgstr "已成功下载备份" + #: src/views/preference/AuthSettings.vue:129 msgid "Ban Threshold Minutes" msgstr "禁止阈值(分钟)" @@ -276,7 +296,7 @@ msgstr "禁止 IP 列表" msgid "Banned Until" msgstr "禁用至" -#: src/views/site/SiteAdd.vue:95 +#: src/views/site/site_add/SiteAdd.vue:95 msgid "Base information" msgstr "基本信息" @@ -382,12 +402,12 @@ msgid "Certificate Status" msgid_plural "Certificates Status" msgstr[0] "证书状态" -#: src/routes/index.ts:139 +#: src/routes/modules/certificates.ts:11 #: src/views/certificate/CertificateList/Certificate.vue:13 msgid "Certificates" msgstr "证书" -#: src/routes/index.ts:156 +#: src/routes/modules/certificates.ts:28 msgid "Certificates List" msgstr "证书列表" @@ -457,6 +477,10 @@ msgstr "清空" msgid "Cleared successfully" msgstr "清除成功" +#: src/views/system/Backup/SystemRestore.vue:137 +msgid "Click or drag backup file to this area to upload" +msgstr "单击或拖动备份文件到此区域上传" + #: src/views/preference/components/TOTP.vue:110 msgid "Click to copy" msgstr "点击复制" @@ -472,6 +496,10 @@ msgstr "命令" msgid "Comments" msgstr "注释" +#: src/constants/errors/backup.ts:13 +msgid "Config path is empty" +msgstr "配置路径为空" + #: src/views/site/ngx_conf/config_template/ConfigTemplate.vue:84 msgid "Config Templates" msgstr "配置" @@ -480,7 +508,7 @@ msgstr "配置" msgid "Configuration file is test successful" msgstr "配置文件测试成功" -#: src/views/site/SiteAdd.vue:101 +#: src/views/site/site_add/SiteAdd.vue:101 msgid "Configuration Name" msgstr "配置名称" @@ -488,7 +516,7 @@ msgstr "配置名称" msgid "Configurations" msgstr "配置" -#: src/views/site/SiteAdd.vue:96 +#: src/views/site/site_add/SiteAdd.vue:96 msgid "Configure SSL" msgstr "配置 SSL" @@ -512,7 +540,12 @@ msgstr "内容" msgid "Copied" msgstr "已拷贝" +#: src/views/system/Backup/BackupCreator.vue:128 +msgid "Copied!" +msgstr "已拷贝!" + #: src/components/SensitiveString/SensitiveString.vue:37 +#: src/views/system/Backup/BackupCreator.vue:128 msgid "Copy" msgstr "拷贝" @@ -536,10 +569,14 @@ msgstr "CPU:" msgid "Create" msgstr "创建" -#: src/views/site/SiteAdd.vue:157 +#: src/views/site/site_add/SiteAdd.vue:157 msgid "Create Another" msgstr "再创建一个" +#: src/views/system/Backup/BackupCreator.vue:86 +msgid "Create Backup" +msgstr "创建备份" + #: src/views/config/ConfigList.vue:116 msgid "Create File" msgstr "创建文件" @@ -548,9 +585,16 @@ msgstr "创建文件" msgid "Create Folder" msgstr "创建文件夹" +#: src/views/system/Backup/BackupCreator.vue:75 +msgid "" +"Create system backups including Nginx configuration and Nginx UI settings. " +"Backup files will be automatically downloaded to your computer." +msgstr "" +"创建系统备份,包括 Nginx 配置和 Nginx UI 设置。备份文件将自动下载到你的电脑。" + #: src/views/notification/notificationColumns.tsx:58 #: src/views/preference/components/Passkey.vue:95 -#: src/views/site/site_category/columns.ts:15 src/views/user/userColumns.tsx:48 +#: src/views/site/site_category/columns.ts:16 src/views/user/userColumns.tsx:48 msgid "Created at" msgstr "创建时间" @@ -593,7 +637,7 @@ msgid "" "indicator." msgstr "自定义显示在环境指示器中的本地服务器名称。" -#: src/routes/index.ts:38 src/views/config/ConfigEditor.vue:134 +#: src/routes/modules/dashboard.ts:10 src/views/config/ConfigEditor.vue:134 #: src/views/config/ConfigEditor.vue:97 src/views/config/ConfigList.vue:64 msgid "Dashboard" msgstr "仪表盘" @@ -770,7 +814,8 @@ msgstr "禁用成功" msgid "Disk IO" msgstr "磁盘 IO" -#: src/routes/index.ts:184 src/views/certificate/DNSCredential.vue:40 +#: src/routes/modules/certificates.ts:56 +#: src/views/certificate/DNSCredential.vue:40 msgid "DNS Credentials" msgstr "DNS 凭证" @@ -874,15 +919,15 @@ msgstr "编辑" msgid "Edit %{n}" msgstr "编辑 %{n}" -#: src/routes/index.ts:128 src/views/config/ConfigEditor.vue:204 +#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:204 msgid "Edit Configuration" msgstr "编辑配置" -#: src/routes/index.ts:78 +#: src/routes/modules/sites.ts:41 msgid "Edit Site" msgstr "编辑站点" -#: src/routes/index.ts:98 +#: src/routes/modules/streams.ts:19 msgid "Edit Stream" msgstr "编辑 Stream" @@ -907,7 +952,7 @@ msgstr "二步验证启用成功" msgid "Enable auto-renewal failed for %{name}" msgstr "启用 %{name} 自动续签失败" -#: src/views/site/SiteAdd.vue:43 +#: src/views/site/site_add/SiteAdd.vue:43 msgid "Enable failed" msgstr "启用失败" @@ -964,8 +1009,9 @@ msgstr "启用 TOTP" msgid "Enabled" msgstr "启用" +#: src/views/site/site_add/SiteAdd.vue:40 #: src/views/site/site_edit/RightSettings.vue:33 -#: src/views/site/site_list/SiteList.vue:46 src/views/site/SiteAdd.vue:40 +#: src/views/site/site_list/SiteList.vue:46 #: src/views/stream/components/RightSettings.vue:29 #: src/views/stream/StreamList.vue:61 msgid "Enabled successfully" @@ -979,7 +1025,8 @@ msgstr "用 Let's Encrypt 对网站进行加密" msgid "Environment variables cleaned" msgstr "环境变量已清理" -#: src/routes/index.ts:234 src/views/dashboard/Environments.vue:83 +#: src/routes/modules/environments.ts:11 +#: src/views/dashboard/Environments.vue:83 #: src/views/environment/Environment.vue:43 msgid "Environments" msgstr "环境" @@ -989,7 +1036,7 @@ msgstr "环境" msgid "Error" msgstr "错误" -#: src/routes/index.ts:217 src/views/site/ngx_conf/LogEntry.vue:83 +#: src/routes/modules/nginx_log.ts:24 src/views/site/ngx_conf/LogEntry.vue:83 msgid "Error Logs" msgstr "错误日志" @@ -1014,10 +1061,114 @@ msgstr "导出" msgid "Fail to obtain certificate" msgstr "获取证书失败" +#: src/constants/errors/backup.ts:5 +msgid "Failed to backup Nginx config files: {0}" +msgstr "备份 Nginx 配置文件失败:{0}" + +#: src/constants/errors/backup.ts:4 +msgid "Failed to backup Nginx UI files: {0}" +msgstr "备份 Nginx UI 文件失败:{0}" + +#: src/constants/errors/backup.ts:17 +msgid "Failed to calculate hash: {0}" +msgstr "计算哈希值失败:{0}" + +#: src/constants/errors/backup.ts:53 +msgid "Failed to calculate Nginx hash: {0}" +msgstr "计算 Nginx 哈希值失败:{0}" + +#: src/constants/errors/backup.ts:52 +msgid "Failed to calculate Nginx UI hash: {0}" +msgstr "计算 Nginx UI 哈希值失败:{0}" + +#: src/constants/errors/backup.ts:14 +msgid "Failed to copy config file: {0}" +msgstr "复制配置文件失败:{0}" + +#: src/constants/errors/backup.ts:15 +msgid "Failed to copy database directory: {0}" +msgstr "复制数据库目录失败:{0}" + +#: src/constants/errors/backup.ts:16 +msgid "Failed to copy database file: {0}" +msgstr "复制数据库文件失败:{0}" + +#: src/constants/errors/backup.ts:30 +msgid "Failed to copy file content: {0}" +msgstr "复制文件内容失败:{0}" + +#: src/constants/errors/backup.ts:19 +msgid "Failed to copy Nginx config directory: {0}" +msgstr "复制 Nginx 配置目录失败:{0}" + #: src/constants/errors/self_check.ts:9 msgid "Failed to create backup" msgstr "创建备份失败" +#: src/constants/errors/backup.ts:12 +msgid "Failed to create backup file: {0}" +msgstr "创建备份文件失败:{0}" + +#: src/constants/errors/backup.ts:44 +msgid "Failed to create directory: {0}" +msgstr "创建目录失败:{0}" + +#: src/constants/errors/backup.ts:46 +msgid "Failed to create file: {0}" +msgstr "创建文件失败:{0}" + +#: src/constants/errors/backup.ts:6 +msgid "Failed to create hash info file: {0}" +msgstr "创建哈希信息文件失败:{0}" + +#: src/constants/errors/backup.ts:45 +msgid "Failed to create parent directory: {0}" +msgstr "创建父目录失败:{0}" + +#: src/constants/errors/backup.ts:32 +msgid "Failed to create restore directory: {0}" +msgstr "创建还原目录失败:{0}" + +#: src/constants/errors/backup.ts:2 +msgid "Failed to create temporary directory" +msgstr "创建临时目录失败" + +#: src/constants/errors/backup.ts:3 +msgid "Failed to create temporary subdirectory" +msgstr "创建临时子目录失败" + +#: src/constants/errors/backup.ts:9 +msgid "Failed to create zip archive: {0}" +msgstr "创建 zip 压缩包失败:{0}" + +#: src/constants/errors/backup.ts:27 +msgid "Failed to create zip entry: {0}" +msgstr "创建 zip 条目失败:{0}" + +#: src/constants/errors/backup.ts:26 +msgid "Failed to create zip file: {0}" +msgstr "创建压缩文件失败:{0}" + +#: src/constants/errors/backup.ts:29 +msgid "Failed to create zip header: {0}" +msgstr "创建 zip 头失败:{0}" + +#: src/constants/errors/backup.ts:24 +msgid "Failed to decrypt data: {0}" +msgstr "解密数据失败:{0}" + +#: src/constants/errors/backup.ts:49 +msgid "Failed to decrypt file: {0}" +msgstr "解密文件失败:{0}" + +#: src/constants/errors/backup.ts:35 +msgid "Failed to decrypt Nginx directory: {0}" +msgstr "解密 Nginx 目录失败:{0}" + +#: src/constants/errors/backup.ts:34 +msgid "Failed to decrypt Nginx UI directory: {0}" +msgstr "解密 Nginx UI 目录失败:{0}" + #: src/views/site/site_edit/RightSettings.vue:45 #: src/views/site/site_list/SiteList.vue:60 #: src/views/stream/components/RightSettings.vue:41 @@ -1032,23 +1183,99 @@ msgstr "禁用失败 %{msg}" msgid "Failed to enable %{msg}" msgstr "启用失败 %{msg}" +#: src/constants/errors/backup.ts:23 +msgid "Failed to encrypt data: {0}" +msgstr "加密数据失败:{0}" + +#: src/constants/errors/backup.ts:21 +msgid "Failed to encrypt file: {0}" +msgstr "加密文件失败:{0}" + +#: src/constants/errors/backup.ts:8 +msgid "Failed to encrypt Nginx directory: {0}" +msgstr "加密 Nginx 目录失败:{0}" + +#: src/constants/errors/backup.ts:7 +msgid "Failed to encrypt Nginx UI directory: {0}" +msgstr "加密 Nginx UI 目录失败:{0}" + +#: src/constants/errors/backup.ts:33 +msgid "Failed to extract archive: {0}" +msgstr "解压缩失败:{0}" + +#: src/constants/errors/backup.ts:10 +msgid "Failed to generate AES key: {0}" +msgstr "生成 AES 密钥失败: {0}" + +#: src/constants/errors/backup.ts:11 +msgid "Failed to generate initialization vector: {0}" +msgstr "生成初始化向量失败:{0}" + #: src/language/constants.ts:5 msgid "Failed to get certificate information" msgstr "获取证书信息失败" +#: src/constants/errors/backup.ts:28 +msgid "Failed to open source file: {0}" +msgstr "打开源文件失败:{0}" + +#: src/constants/errors/backup.ts:47 +msgid "Failed to open zip entry: {0}" +msgstr "打开 zip 条目失败:{0}" + +#: src/constants/errors/backup.ts:43 +msgid "Failed to open zip file: {0}" +msgstr "打开压缩文件失败:{0}" + #: src/constants/errors/self_check.ts:4 msgid "Failed to parse nginx.conf" msgstr "解析 nginx.conf 失败" +#: src/constants/errors/backup.ts:48 +msgid "Failed to read encrypted file: {0}" +msgstr "读取加密文件失败:{0}" + +#: src/constants/errors/backup.ts:20 +msgid "Failed to read file: {0}" +msgstr "读取文件失败:{0}" + +#: src/constants/errors/backup.ts:51 +msgid "Failed to read hash info file: {0}" +msgstr "读取哈希信息文件失败:{0}" + #: src/constants/errors/self_check.ts:3 msgid "Failed to read nginx.conf" msgstr "读取 nginx.conf 失败" +#: src/constants/errors/backup.ts:37 +msgid "Failed to restore Nginx configs: {0}" +msgstr "恢复 Nginx 配置失败:{0}" + +#: src/constants/errors/backup.ts:38 +msgid "Failed to restore Nginx UI files: {0}" +msgstr "恢复 Nginx UI 文件失败:{0}" + #: src/views/site/site_edit/SiteEdit.vue:135 #: src/views/stream/StreamEdit.vue:122 msgid "Failed to save, syntax error(s) was detected in the configuration." msgstr "保存失败,在配置中检测到语法错误。" +#: src/constants/errors/backup.ts:36 +msgid "Failed to verify hashes: {0}" +msgstr "验证哈希值失败:{0}" + +#: src/constants/errors/backup.ts:50 +msgid "Failed to write decrypted file: {0}" +msgstr "写入解密文件失败:{0}" + +#: src/constants/errors/backup.ts:22 +msgid "Failed to write encrypted file: {0}" +msgstr "写入加密文件失败:{0}" + +#: src/constants/errors/backup.ts:31 +msgid "Failed to write to zip buffer: {0}" +msgstr "写入 zip 缓冲区失败:{0}" + #: src/language/constants.ts:32 msgid "File exists" msgstr "文件已存在" @@ -1065,7 +1292,7 @@ msgstr "文件名为空" msgid "Filter" msgstr "过滤" -#: src/language/constants.ts:19 src/views/site/SiteAdd.vue:97 +#: src/language/constants.ts:19 src/views/site/site_add/SiteAdd.vue:97 msgid "Finished" msgstr "完成" @@ -1137,11 +1364,15 @@ msgstr "正在获取证书,请稍等..." msgid "Github Proxy" msgstr "Github代理" +#: src/constants/errors/backup.ts:54 +msgid "Hash verification failed: file integrity compromised" +msgstr "哈希验证失败:文件完整性受损" + #: src/components/SensitiveString/SensitiveString.vue:40 msgid "Hide" msgstr "隐藏" -#: src/routes/index.ts:30 +#: src/routes/index.ts:47 msgid "Home" msgstr "首页" @@ -1191,7 +1422,8 @@ msgstr "如果您的域名有 CNAME 记录且无法获取证书,则需要启 msgid "Import" msgstr "导入" -#: src/routes/index.ts:174 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:46 +#: src/views/certificate/CertificateEditor.vue:85 msgid "Import Certificate" msgstr "导入证书" @@ -1216,7 +1448,7 @@ msgstr "输入应用程序中的代码:" msgid "Input the recovery code:" msgstr "输入恢复代码:" -#: src/routes/index.ts:312 src/views/other/Install.vue:134 +#: src/routes/modules/auth.ts:8 src/views/other/Install.vue:134 msgid "Install" msgstr "安装" @@ -1232,6 +1464,18 @@ msgstr "间隔" msgid "Invalid" msgstr "无效的" +#: src/constants/errors/backup.ts:42 +msgid "Invalid AES IV format: {0}" +msgstr "AES IV 格式无效:{0}" + +#: src/constants/errors/backup.ts:41 +msgid "Invalid AES key format: {0}" +msgstr "AES 密钥格式无效:{0}" + +#: src/views/system/Backup/SystemRestore.vue:67 +msgid "Invalid file object" +msgstr "无效文件对象" + #: src/views/config/components/Rename.vue:64 #: src/views/config/ConfigEditor.vue:250 msgid "Invalid filename" @@ -1245,6 +1489,10 @@ msgstr "无效文件夹名" msgid "Invalid otp code" msgstr "无效的 OTP 代码" +#: src/constants/errors/backup.ts:25 +msgid "Invalid padding in decrypted data" +msgstr "解密数据中的无效填充" + #: src/components/TwoFA/use2FAModal.ts:61 msgid "Invalid passcode or recovery code" msgstr "二次验证码或恢复代码无效" @@ -1257,6 +1505,10 @@ msgstr "无效的恢复代码" msgid "Invalid request format" msgstr "无效的请求格式" +#: src/constants/errors/backup.ts:40 +msgid "Invalid security token format" +msgstr "安全令牌格式无效" + #: src/views/preference/AuthSettings.vue:18 msgid "IP" msgstr "IP" @@ -1372,7 +1624,7 @@ msgstr "Locations" msgid "Log" msgstr "日志" -#: src/routes/index.ts:318 src/views/other/Login.vue:222 +#: src/routes/modules/auth.ts:14 src/views/other/Login.vue:222 msgid "Login" msgstr "登录" @@ -1410,20 +1662,20 @@ msgstr "" "在获取签发证书前,请确保配置文件中已将 .well-known 目录反向代理到 " "HTTPChallengePort。" -#: src/routes/index.ts:108 src/views/config/ConfigEditor.vue:102 +#: src/routes/modules/config.ts:10 src/views/config/ConfigEditor.vue:102 #: src/views/config/ConfigEditor.vue:139 src/views/config/ConfigList.vue:69 msgid "Manage Configs" msgstr "配置管理" -#: src/routes/index.ts:47 src/views/site/site_list/SiteList.vue:94 +#: src/routes/modules/sites.ts:10 src/views/site/site_list/SiteList.vue:94 msgid "Manage Sites" msgstr "网站管理" -#: src/routes/index.ts:89 src/views/stream/StreamList.vue:119 +#: src/routes/modules/streams.ts:10 src/views/stream/StreamList.vue:119 msgid "Manage Streams" msgstr "管理 Stream" -#: src/routes/index.ts:257 src/views/user/User.vue:10 +#: src/routes/modules/user.ts:10 src/views/user/User.vue:10 msgid "Manage Users" msgstr "用户管理" @@ -1459,11 +1711,12 @@ msgstr "模型" msgid "Modify" msgstr "修改" -#: src/routes/index.ts:164 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:36 +#: src/views/certificate/CertificateEditor.vue:85 msgid "Modify Certificate" msgstr "修改证书" -#: src/views/site/SiteAdd.vue:154 +#: src/views/site/site_add/SiteAdd.vue:154 msgid "Modify Config" msgstr "修改配置文件" @@ -1524,7 +1777,7 @@ msgstr "新版本发布" #: src/views/certificate/WildcardCertificate.vue:91 #: src/views/site/cert/components/ObtainCert.vue:211 -#: src/views/site/SiteAdd.vue:141 +#: src/views/site/site_add/SiteAdd.vue:141 msgid "Next" msgstr "下一步" @@ -1560,6 +1813,14 @@ msgstr "Nginx Conf 中未引用 sites-enabled" msgid "Nginx conf not include stream-enabled" msgstr "Nginx Conf 中未引用 stream-enabled" +#: src/constants/errors/backup.ts:18 +msgid "Nginx config directory is not set" +msgstr "未设置 Nginx 配置目录" + +#: src/views/system/Backup/SystemRestore.vue:84 +msgid "Nginx configuration has been restored" +msgstr "Nginx 配置已恢复" + #: src/views/site/site_edit/SiteEdit.vue:223 #: src/views/stream/StreamEdit.vue:208 msgid "Nginx Configuration Parse Error" @@ -1581,7 +1842,7 @@ msgstr "Nginx 错误日志路径" msgid "Nginx is not running" msgstr "Nginx 未启动" -#: src/routes/index.ts:202 src/views/nginx_log/NginxLog.vue:148 +#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:148 msgid "Nginx Log" msgstr "Nginx 日志" @@ -1609,6 +1870,16 @@ msgstr "Nginx 重启命令" msgid "Nginx restarted successfully" msgstr "Nginx 重启成功" +#: src/views/system/Backup/SystemRestore.vue:88 +msgid "Nginx UI configuration has been restored" +msgstr "Nginx 用户界面配置已恢复" + +#: src/views/system/Backup/SystemRestore.vue:93 +msgid "" +"Nginx UI configuration has been restored and will restart automatically in a " +"few seconds." +msgstr "Nginx UI 配置已恢复,几秒钟后将自动重启。" + #: src/components/ChatGPT/ChatGPT.vue:374 #: src/components/Notification/Notification.vue:133 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:63 @@ -1638,7 +1909,7 @@ msgstr "节点密钥" msgid "Not After" msgstr "有效期" -#: src/routes/index.ts:324 +#: src/routes/modules/error.ts:8 msgid "Not Found" msgstr "找不到页面" @@ -1661,7 +1932,8 @@ msgstr "注意,如果配置文件中包含其他配置或证书,请提前将 msgid "Notification" msgstr "通知" -#: src/components/Notification/Notification.vue:131 src/routes/index.ts:248 +#: src/components/Notification/Notification.vue:131 +#: src/routes/modules/notifications.ts:10 msgid "Notifications" msgstr "通知" @@ -1709,6 +1981,8 @@ msgstr "确定" #: src/views/site/site_list/SiteList.vue:144 #: src/views/stream/components/RightSettings.vue:50 #: src/views/stream/StreamList.vue:164 +#: src/views/system/Backup/BackupCreator.vue:149 +#: src/views/system/Backup/SystemRestore.vue:94 msgid "OK" msgstr "确定" @@ -1723,6 +1997,10 @@ msgstr "一旦验证完成,这些记录将被删除。" msgid "Online" msgstr "在线" +#: src/views/system/Backup/SystemRestore.vue:24 +msgid "Only zip files are allowed" +msgstr "只允许使用zip文件" + #: src/views/preference/Preference.vue:170 msgid "OpenAI" msgstr "OpenAI" @@ -1832,6 +2110,14 @@ msgstr "请为您要创建的 Passkey 输入一个名称,然后单击下面的 msgid "Please enter the OTP code:" msgstr "请输入 OTP:" +#: src/views/system/Backup/SystemRestore.vue:58 +msgid "Please enter the security token" +msgstr "请输入安全令牌" + +#: src/views/system/Backup/SystemRestore.vue:153 +msgid "Please enter the security token received during backup" +msgstr "请输入备份时收到的安全令牌" + #: src/views/certificate/DNSCredential.vue:53 msgid "" "Please fill in the API authentication credentials provided by your DNS " @@ -1895,6 +2181,14 @@ msgid "" "Please note that the unit of time configurations below are all in seconds." msgstr "请注意,下面的时间单位配置均以秒为单位。" +#: src/views/system/Backup/BackupCreator.vue:107 +msgid "Please save this security token, you will need it for restoration:" +msgstr "请保存此安全令牌,恢复时会用到它:" + +#: src/views/system/Backup/SystemRestore.vue:53 +msgid "Please select a backup file" +msgstr "请选择备份文件" + #: src/views/environment/Environment.vue:58 msgid "Please select at least one node to upgrade" msgstr "请至少选择一个节点进行升级" @@ -1905,7 +2199,7 @@ msgstr "请至少选择一个节点进行升级" msgid "Pre-release" msgstr "预发布" -#: src/routes/index.ts:266 src/views/preference/Preference.vue:141 +#: src/routes/modules/preference.ts:10 src/views/preference/Preference.vue:141 msgid "Preference" msgstr "偏好设置" @@ -2161,6 +2455,18 @@ msgstr "重启" msgid "Restarting" msgstr "重启中" +#: src/views/system/Backup/SystemRestore.vue:81 +msgid "Restore completed successfully" +msgstr "恢复成功" + +#: src/views/system/Backup/SystemRestore.vue:165 +msgid "Restore Nginx Configuration" +msgstr "恢复 Nginx 配置" + +#: src/views/system/Backup/SystemRestore.vue:176 +msgid "Restore Nginx UI Configuration" +msgstr "恢复 Nginx UI 配置" + #: src/views/preference/AuthSettings.vue:107 msgid "RP Display Name" msgstr "依赖方显示名称" @@ -2203,7 +2509,7 @@ msgstr "保存指令" #: src/views/config/ConfigEditor.vue:171 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:41 -#: src/views/site/SiteAdd.vue:46 +#: src/views/site/site_add/SiteAdd.vue:46 msgid "Save error %{msg}" msgstr "保存错误 %{msg}" @@ -2248,7 +2554,8 @@ msgstr "保存成功" #: src/views/config/ConfigEditor.vue:167 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:39 -#: src/views/site/site_edit/SiteEdit.vue:152 src/views/site/SiteAdd.vue:37 +#: src/views/site/site_add/SiteAdd.vue:37 +#: src/views/site/site_edit/SiteEdit.vue:152 #: src/views/stream/StreamEdit.vue:139 msgid "Saved successfully" msgstr "保存成功" @@ -2265,11 +2572,19 @@ msgstr "SDK" msgid "Secret has been copied" msgstr "密钥已复制" +#: src/views/system/Backup/SystemRestore.vue:150 +msgid "Security Token" +msgstr "安全 Token" + +#: src/views/system/Backup/BackupCreator.vue:94 +msgid "Security Token Information" +msgstr "安全令牌信息" + #: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:189 msgid "Selector" msgstr "选择器" -#: src/routes/index.ts:283 src/views/system/SelfCheck/SelfCheck.vue:42 +#: src/routes/modules/system.ts:19 src/views/system/SelfCheck/SelfCheck.vue:42 msgid "Self Check" msgstr "自我检查" @@ -2340,11 +2655,12 @@ msgstr "使用 Passkey 登录" msgid "Single Directive" msgstr "单行指令" -#: src/routes/index.ts:71 src/views/site/site_category/SiteCategory.vue:10 +#: src/routes/modules/sites.ts:34 +#: src/views/site/site_category/SiteCategory.vue:10 msgid "Site Categories" msgstr "网站分类" -#: src/views/site/SiteAdd.vue:147 +#: src/views/site/site_add/SiteAdd.vue:147 msgid "Site Config Created Successfully" msgstr "网站配置创建成功" @@ -2352,7 +2668,7 @@ msgstr "网站配置创建成功" msgid "Site is enabled" msgstr "网站已启用" -#: src/routes/index.ts:224 +#: src/routes/modules/nginx_log.ts:31 msgid "Site Logs" msgstr "站点列表" @@ -2364,7 +2680,7 @@ msgstr "网站未找到" msgid "Sites Directory" msgstr "网站目录" -#: src/routes/index.ts:56 +#: src/routes/modules/sites.ts:19 msgid "Sites List" msgstr "站点列表" @@ -2402,6 +2718,10 @@ msgstr "SSO 登录" msgid "Stable" msgstr "稳定" +#: src/views/system/Backup/SystemRestore.vue:187 +msgid "Start Restore" +msgstr "开始还原" + #: src/views/certificate/ACMEUser.vue:65 #: src/views/certificate/CertificateList/certColumns.tsx:68 #: src/views/environment/envColumns.tsx:44 @@ -2452,6 +2772,10 @@ msgstr "" "支持通过 WebSocket 协议与后端通信,如果您正在使用 Nginx 反向代理了 Nginx UI " "请参考:https://nginxui.com/guide/nginx-proxy-example.html 编写配置文件" +#: src/views/system/Backup/SystemRestore.vue:140 +msgid "Supported file type: .zip" +msgstr "支持的文件类型:.zip" + #: src/views/dashboard/ServerAnalytic.vue:236 #: src/views/dashboard/ServerAnalytic.vue:237 msgid "Swap" @@ -2506,7 +2830,7 @@ msgstr "同步配置错误" msgid "Sync Config Success" msgstr "同步配置成功" -#: src/views/site/site_category/SiteCategory.vue:17 +#: src/views/site/site_category/SiteCategory.vue:18 msgid "Sync Nodes" msgstr "同步节点" @@ -2523,19 +2847,27 @@ msgstr "同步到" msgid "Synchronization" msgstr "同步" -#: src/routes/index.ts:275 +#: src/routes/modules/system.ts:11 msgid "System" msgstr "系统" +#: src/views/system/Backup/BackupCreator.vue:71 +msgid "System Backup" +msgstr "系统备份" + #: src/views/certificate/ACMEUserSelector.vue:88 msgid "System Initial User" msgstr "系统初始用户" +#: src/views/system/Backup/SystemRestore.vue:117 +msgid "System Restore" +msgstr "系统还原" + #: src/constants/errors/self_check.ts:2 msgid "Task not found" msgstr "未找到任务" -#: src/routes/index.ts:194 src/views/terminal/Terminal.vue:114 +#: src/routes/modules/terminal.ts:10 src/views/terminal/Terminal.vue:114 msgid "Terminal" msgstr "终端" @@ -2587,7 +2919,7 @@ msgid "" "dashes, colons, and dots." msgstr "节点名称只能包含字母、统一码、数字、连字符、破折号、冒号和点。" -#: src/views/site/SiteAdd.vue:120 +#: src/views/site/site_add/SiteAdd.vue:120 msgid "The parameter of server_name is required" msgstr "必须为 server_name 指令指明参数" @@ -2675,10 +3007,28 @@ msgid "" "This field should only contain letters, unicode characters, numbers, and -_." msgstr "该字段只能包含字母、unicode 字符、数字和 -_。" +#: src/views/system/Backup/BackupCreator.vue:141 +msgid "" +"This token will only be shown once and cannot be retrieved later. Please " +"make sure to save it in a secure location." +msgstr "此 Token 只显示一次,以后无法找回。请确保将其保存在安全位置。" + #: src/constants/form_errors.ts:4 msgid "This value is already taken" msgstr "该字段的值已经存在" +#: src/views/system/Backup/SystemRestore.vue:169 +msgid "" +"This will restore all Nginx configuration files. Nginx will restart after " +"the restoration is complete." +msgstr "这将还原所有 Nginx 配置文件。恢复完成后,Nginx 将重新启动。" + +#: src/views/system/Backup/SystemRestore.vue:180 +msgid "" +"This will restore configuration files and database. Nginx UI will restart " +"after the restoration is complete." +msgstr "这将恢复配置文件和数据库。恢复完成后,Nginx UI 将重新启动。" + #: src/views/environment/BatchUpgrader.vue:182 msgid "" "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}." @@ -2785,7 +3135,7 @@ msgstr "修改时间" msgid "Updated successfully" msgstr "更新成功" -#: src/routes/index.ts:297 src/views/environment/Environment.vue:66 +#: src/routes/modules/system.ts:40 src/views/environment/Environment.vue:66 #: src/views/system/Upgrade.vue:143 src/views/system/Upgrade.vue:226 msgid "Upgrade" msgstr "升级" @@ -2848,6 +3198,10 @@ msgstr "用户名 (*)" msgid "Valid" msgstr "有效的" +#: src/views/system/Backup/SystemRestore.vue:159 +msgid "Verify Backup File Integrity" +msgstr "验证备份文件的完整性" + #: src/views/environment/envColumns.tsx:31 msgid "Version" msgstr "版本" @@ -2880,10 +3234,20 @@ msgstr "已查看" #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33 #: src/views/notification/notificationColumns.tsx:22 #: src/views/preference/components/AddPasskey.vue:82 -#: src/views/site/SiteAdd.vue:115 +#: src/views/site/site_add/SiteAdd.vue:115 +#: src/views/system/Backup/BackupCreator.vue:138 msgid "Warning" msgstr "警告" +#: src/views/system/Backup/SystemRestore.vue:121 +msgid "" +"Warning: Restore operation will overwrite current configurations. Make sure " +"you have a valid backup file and security token, and carefully select what " +"to restore." +msgstr "" +"警告:还原操作将覆盖当前配置。请确保您有有效的备份文件和安全令牌,并仔细选择" +"要还原的内容。" + #: src/views/certificate/DNSCredential.vue:56 msgid "" "We will add one or more TXT records to the DNS records of your domain for " @@ -2986,6 +3350,9 @@ msgstr "您的旧代码将不再有效。" msgid "Your passkeys" msgstr "你的 Passkeys" +#~ msgid "Restart Required" +#~ msgstr "必须重新启动" + #~ msgid "Deploy %{conf_name} to %{node_name} successfully" #~ msgstr "部署 %{conf_name} 到 %{node_name} 成功" @@ -3017,9 +3384,6 @@ msgstr "你的 Passkeys" #~ msgid "Enable successfully" #~ msgstr "启用成功" -#~ msgid "Please select at least one node!" -#~ msgstr "请至少选择一个节点!" - #~ msgid "Please upgrade the remote Nginx UI to the latest version" #~ msgstr "请将远程 Nginx UI 升级到最新版本" diff --git a/app/src/language/zh_TW/app.po b/app/src/language/zh_TW/app.po index 0509079e..ffee15b7 100644 --- a/app/src/language/zh_TW/app.po +++ b/app/src/language/zh_TW/app.po @@ -27,15 +27,15 @@ msgstr "雙因素驗證" msgid "2FA Settings" msgstr "多重要素驗證設定" -#: src/routes/index.ts:290 +#: src/routes/modules/system.ts:26 msgid "About" msgstr "關於" -#: src/routes/index.ts:210 src/views/site/ngx_conf/LogEntry.vue:75 +#: src/routes/modules/nginx_log.ts:17 src/views/site/ngx_conf/LogEntry.vue:75 msgid "Access Logs" msgstr "訪問日誌" -#: src/routes/index.ts:148 src/views/certificate/ACMEUser.vue:113 +#: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:113 #: src/views/certificate/ACMEUserSelector.vue:85 msgid "ACME User" msgstr "ACME 用戶" @@ -47,7 +47,7 @@ msgstr "ACME 用戶" #: src/views/environment/envColumns.tsx:97 #: src/views/notification/notificationColumns.tsx:65 #: src/views/preference/AuthSettings.vue:30 -#: src/views/site/site_category/columns.ts:29 +#: src/views/site/site_category/columns.ts:28 #: src/views/site/site_list/columns.tsx:76 src/views/stream/StreamList.vue:49 #: src/views/user/userColumns.tsx:60 msgid "Action" @@ -68,7 +68,7 @@ msgstr "新增" msgid "Add a passkey" msgstr "新增通行密鑰" -#: src/routes/index.ts:118 src/views/config/ConfigEditor.vue:144 +#: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:144 #: src/views/config/ConfigEditor.vue:204 msgid "Add Configuration" msgstr "添加配置" @@ -82,7 +82,7 @@ msgstr "在下方新增指令" msgid "Add Location" msgstr "新增 Location" -#: src/routes/index.ts:63 src/views/site/SiteAdd.vue:89 +#: src/routes/modules/sites.ts:26 src/views/site/site_add/SiteAdd.vue:89 msgid "Add Site" msgstr "新增網站" @@ -252,6 +252,10 @@ msgstr "已關閉 %{name} 的自動續簽" msgid "Auto-renewal enabled for %{name}" msgstr "已啟用 %{name} 的自動續簽" +#: src/views/system/Backup/SystemRestore.vue:92 +msgid "Automatic Restart" +msgstr "" + #: src/views/certificate/CertificateEditor.vue:255 #: src/views/config/ConfigEditor.vue:213 src/views/config/ConfigList.vue:106 #: src/views/config/ConfigList.vue:180 src/views/nginx_log/NginxLog.vue:173 @@ -268,6 +272,25 @@ msgstr "返回首頁" msgid "Back to list" msgstr "返回列表" +#: src/routes/modules/system.ts:33 +#, fuzzy +msgid "Backup" +msgstr "返回" + +#: src/views/system/Backup/SystemRestore.vue:100 +msgid "Backup file integrity check failed, it may have been tampered with" +msgstr "" + +#: src/constants/errors/backup.ts:39 +#, fuzzy +msgid "Backup file not found: {0}" +msgstr "站點未找到" + +#: src/views/system/Backup/BackupCreator.vue:42 +#, fuzzy +msgid "Backup has been downloaded successfully" +msgstr "Nginx 重新載入成功" + #: src/views/preference/AuthSettings.vue:129 msgid "Ban Threshold Minutes" msgstr "封禁閾值分鐘數" @@ -280,7 +303,7 @@ msgstr "被禁止的 IP" msgid "Banned Until" msgstr "禁止至" -#: src/views/site/SiteAdd.vue:95 +#: src/views/site/site_add/SiteAdd.vue:95 msgid "Base information" msgstr "基本資訊" @@ -386,12 +409,12 @@ msgid "Certificate Status" msgid_plural "Certificates Status" msgstr[0] "憑證狀態" -#: src/routes/index.ts:139 +#: src/routes/modules/certificates.ts:11 #: src/views/certificate/CertificateList/Certificate.vue:13 msgid "Certificates" msgstr "憑證" -#: src/routes/index.ts:156 +#: src/routes/modules/certificates.ts:28 msgid "Certificates List" msgstr "憑證清單" @@ -463,6 +486,10 @@ msgstr "清除" msgid "Cleared successfully" msgstr "清除成功" +#: src/views/system/Backup/SystemRestore.vue:137 +msgid "Click or drag backup file to this area to upload" +msgstr "" + #: src/views/preference/components/TOTP.vue:110 msgid "Click to copy" msgstr "點擊複製" @@ -478,6 +505,11 @@ msgstr "命令" msgid "Comments" msgstr "備註" +#: src/constants/errors/backup.ts:13 +#, fuzzy +msgid "Config path is empty" +msgstr "明文為空" + #: src/views/site/ngx_conf/config_template/ConfigTemplate.vue:84 msgid "Config Templates" msgstr "設定模板" @@ -486,7 +518,7 @@ msgstr "設定模板" msgid "Configuration file is test successful" msgstr "設定檔案測試成功" -#: src/views/site/SiteAdd.vue:101 +#: src/views/site/site_add/SiteAdd.vue:101 msgid "Configuration Name" msgstr "設定名稱" @@ -494,7 +526,7 @@ msgstr "設定名稱" msgid "Configurations" msgstr "設定" -#: src/views/site/SiteAdd.vue:96 +#: src/views/site/site_add/SiteAdd.vue:96 msgid "Configure SSL" msgstr "設定 SSL" @@ -518,7 +550,13 @@ msgstr "內容" msgid "Copied" msgstr "已複製" +#: src/views/system/Backup/BackupCreator.vue:128 +#, fuzzy +msgid "Copied!" +msgstr "已複製" + #: src/components/SensitiveString/SensitiveString.vue:37 +#: src/views/system/Backup/BackupCreator.vue:128 msgid "Copy" msgstr "複製" @@ -542,10 +580,15 @@ msgstr "中央處理器:" msgid "Create" msgstr "創建" -#: src/views/site/SiteAdd.vue:157 +#: src/views/site/site_add/SiteAdd.vue:157 msgid "Create Another" msgstr "再建立一個" +#: src/views/system/Backup/BackupCreator.vue:86 +#, fuzzy +msgid "Create Backup" +msgstr "建立時間" + #: src/views/config/ConfigList.vue:116 msgid "Create File" msgstr "創建檔案" @@ -554,9 +597,15 @@ msgstr "創建檔案" msgid "Create Folder" msgstr "創建資料夾" +#: src/views/system/Backup/BackupCreator.vue:75 +msgid "" +"Create system backups including Nginx configuration and Nginx UI settings. " +"Backup files will be automatically downloaded to your computer." +msgstr "" + #: src/views/notification/notificationColumns.tsx:58 #: src/views/preference/components/Passkey.vue:95 -#: src/views/site/site_category/columns.ts:15 src/views/user/userColumns.tsx:48 +#: src/views/site/site_category/columns.ts:16 src/views/user/userColumns.tsx:48 msgid "Created at" msgstr "建立時間" @@ -599,7 +648,7 @@ msgid "" "indicator." msgstr "自訂顯示在環境指示器中的本地節點名稱。" -#: src/routes/index.ts:38 src/views/config/ConfigEditor.vue:134 +#: src/routes/modules/dashboard.ts:10 src/views/config/ConfigEditor.vue:134 #: src/views/config/ConfigEditor.vue:97 src/views/config/ConfigList.vue:64 msgid "Dashboard" msgstr "儀表板" @@ -780,7 +829,8 @@ msgstr "成功停用" msgid "Disk IO" msgstr "磁碟 IO" -#: src/routes/index.ts:184 src/views/certificate/DNSCredential.vue:40 +#: src/routes/modules/certificates.ts:56 +#: src/views/certificate/DNSCredential.vue:40 msgid "DNS Credentials" msgstr "DNS 認證" @@ -884,15 +934,15 @@ msgstr "編輯" msgid "Edit %{n}" msgstr "編輯 %{n}" -#: src/routes/index.ts:128 src/views/config/ConfigEditor.vue:204 +#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:204 msgid "Edit Configuration" msgstr "編輯設定" -#: src/routes/index.ts:78 +#: src/routes/modules/sites.ts:41 msgid "Edit Site" msgstr "編輯網站" -#: src/routes/index.ts:98 +#: src/routes/modules/streams.ts:19 msgid "Edit Stream" msgstr "編輯 Stream" @@ -917,7 +967,7 @@ msgstr "啟用多因素身份驗證成功" msgid "Enable auto-renewal failed for %{name}" msgstr "啟用 %{name} 自動續簽失敗" -#: src/views/site/SiteAdd.vue:43 +#: src/views/site/site_add/SiteAdd.vue:43 msgid "Enable failed" msgstr "啟用失敗" @@ -980,8 +1030,9 @@ msgstr "啟用 TOTP" msgid "Enabled" msgstr "已啟用" +#: src/views/site/site_add/SiteAdd.vue:40 #: src/views/site/site_edit/RightSettings.vue:33 -#: src/views/site/site_list/SiteList.vue:46 src/views/site/SiteAdd.vue:40 +#: src/views/site/site_list/SiteList.vue:46 #: src/views/stream/components/RightSettings.vue:29 #: src/views/stream/StreamList.vue:61 msgid "Enabled successfully" @@ -995,7 +1046,8 @@ msgstr "用 Let's Encrypt 對網站進行加密" msgid "Environment variables cleaned" msgstr "環境變數已清理" -#: src/routes/index.ts:234 src/views/dashboard/Environments.vue:83 +#: src/routes/modules/environments.ts:11 +#: src/views/dashboard/Environments.vue:83 #: src/views/environment/Environment.vue:43 msgid "Environments" msgstr "環境" @@ -1005,7 +1057,7 @@ msgstr "環境" msgid "Error" msgstr "錯誤" -#: src/routes/index.ts:217 src/views/site/ngx_conf/LogEntry.vue:83 +#: src/routes/modules/nginx_log.ts:24 src/views/site/ngx_conf/LogEntry.vue:83 msgid "Error Logs" msgstr "錯誤日誌" @@ -1030,10 +1082,130 @@ msgstr "匯出" msgid "Fail to obtain certificate" msgstr "獲取憑證失敗" +#: src/constants/errors/backup.ts:5 +#, fuzzy +msgid "Failed to backup Nginx config files: {0}" +msgstr "讀取 nginx.conf 失敗" + +#: src/constants/errors/backup.ts:4 +msgid "Failed to backup Nginx UI files: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:17 +#, fuzzy +msgid "Failed to calculate hash: {0}" +msgstr "創建備份失敗" + +#: src/constants/errors/backup.ts:53 +msgid "Failed to calculate Nginx hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:52 +msgid "Failed to calculate Nginx UI hash: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:14 +msgid "Failed to copy config file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:15 +msgid "Failed to copy database directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:16 +#, fuzzy +msgid "Failed to copy database file: {0}" +msgstr "停用 %{msg} 失敗" + +#: src/constants/errors/backup.ts:30 +msgid "Failed to copy file content: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:19 +msgid "Failed to copy Nginx config directory: {0}" +msgstr "" + #: src/constants/errors/self_check.ts:9 msgid "Failed to create backup" msgstr "創建備份失敗" +#: src/constants/errors/backup.ts:12 +#, fuzzy +msgid "Failed to create backup file: {0}" +msgstr "創建備份失敗" + +#: src/constants/errors/backup.ts:44 +#, fuzzy +msgid "Failed to create directory: {0}" +msgstr "創建備份失敗" + +#: src/constants/errors/backup.ts:46 +#, fuzzy +msgid "Failed to create file: {0}" +msgstr "創建備份失敗" + +#: src/constants/errors/backup.ts:6 +#, fuzzy +msgid "Failed to create hash info file: {0}" +msgstr "創建備份失敗" + +#: src/constants/errors/backup.ts:45 +#, fuzzy +msgid "Failed to create parent directory: {0}" +msgstr "創建備份失敗" + +#: src/constants/errors/backup.ts:32 +msgid "Failed to create restore directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:2 +#, fuzzy +msgid "Failed to create temporary directory" +msgstr "創建備份失敗" + +#: src/constants/errors/backup.ts:3 +#, fuzzy +msgid "Failed to create temporary subdirectory" +msgstr "創建備份失敗" + +#: src/constants/errors/backup.ts:9 +#, fuzzy +msgid "Failed to create zip archive: {0}" +msgstr "創建備份失敗" + +#: src/constants/errors/backup.ts:27 +#, fuzzy +msgid "Failed to create zip entry: {0}" +msgstr "創建備份失敗" + +#: src/constants/errors/backup.ts:26 +#, fuzzy +msgid "Failed to create zip file: {0}" +msgstr "創建備份失敗" + +#: src/constants/errors/backup.ts:29 +#, fuzzy +msgid "Failed to create zip header: {0}" +msgstr "創建備份失敗" + +#: src/constants/errors/backup.ts:24 +#, fuzzy +msgid "Failed to decrypt data: {0}" +msgstr "創建備份失敗" + +#: src/constants/errors/backup.ts:49 +#, fuzzy +msgid "Failed to decrypt file: {0}" +msgstr "停用 %{msg} 失敗" + +#: src/constants/errors/backup.ts:35 +msgid "Failed to decrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:34 +msgid "Failed to decrypt Nginx UI directory: {0}" +msgstr "" + #: src/views/site/site_edit/RightSettings.vue:45 #: src/views/site/site_list/SiteList.vue:60 #: src/views/stream/components/RightSettings.vue:41 @@ -1048,23 +1220,113 @@ msgstr "停用 %{msg} 失敗" msgid "Failed to enable %{msg}" msgstr "啟用 %{msg} 失敗" +#: src/constants/errors/backup.ts:23 +#, fuzzy +msgid "Failed to encrypt data: {0}" +msgstr "啟用 %{msg} 失敗" + +#: src/constants/errors/backup.ts:21 +#, fuzzy +msgid "Failed to encrypt file: {0}" +msgstr "啟用 %{msg} 失敗" + +#: src/constants/errors/backup.ts:8 +msgid "Failed to encrypt Nginx directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:7 +msgid "Failed to encrypt Nginx UI directory: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:33 +#, fuzzy +msgid "Failed to extract archive: {0}" +msgstr "啟用 %{msg} 失敗" + +#: src/constants/errors/backup.ts:10 +#, fuzzy +msgid "Failed to generate AES key: {0}" +msgstr "啟用 %{msg} 失敗" + +#: src/constants/errors/backup.ts:11 +#, fuzzy +msgid "Failed to generate initialization vector: {0}" +msgstr "取得憑證資訊失敗" + #: src/language/constants.ts:5 msgid "Failed to get certificate information" msgstr "取得憑證資訊失敗" +#: src/constants/errors/backup.ts:28 +#, fuzzy +msgid "Failed to open source file: {0}" +msgstr "啟用 %{msg} 失敗" + +#: src/constants/errors/backup.ts:47 +#, fuzzy +msgid "Failed to open zip entry: {0}" +msgstr "啟用 %{msg} 失敗" + +#: src/constants/errors/backup.ts:43 +#, fuzzy +msgid "Failed to open zip file: {0}" +msgstr "啟用 %{msg} 失敗" + #: src/constants/errors/self_check.ts:4 msgid "Failed to parse nginx.conf" msgstr "解析 nginx.conf 失敗" +#: src/constants/errors/backup.ts:48 +#, fuzzy +msgid "Failed to read encrypted file: {0}" +msgstr "讀取 nginx.conf 失敗" + +#: src/constants/errors/backup.ts:20 +#, fuzzy +msgid "Failed to read file: {0}" +msgstr "啟用 %{msg} 失敗" + +#: src/constants/errors/backup.ts:51 +#, fuzzy +msgid "Failed to read hash info file: {0}" +msgstr "讀取 nginx.conf 失敗" + #: src/constants/errors/self_check.ts:3 msgid "Failed to read nginx.conf" msgstr "讀取 nginx.conf 失敗" +#: src/constants/errors/backup.ts:37 +#, fuzzy +msgid "Failed to restore Nginx configs: {0}" +msgstr "解析 nginx.conf 失敗" + +#: src/constants/errors/backup.ts:38 +#, fuzzy +msgid "Failed to restore Nginx UI files: {0}" +msgstr "解析 nginx.conf 失敗" + #: src/views/site/site_edit/SiteEdit.vue:135 #: src/views/stream/StreamEdit.vue:122 msgid "Failed to save, syntax error(s) was detected in the configuration." msgstr "儲存失敗,在設定中檢測到語法錯誤。" +#: src/constants/errors/backup.ts:36 +#, fuzzy +msgid "Failed to verify hashes: {0}" +msgstr "啟用 %{msg} 失敗" + +#: src/constants/errors/backup.ts:50 +msgid "Failed to write decrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:22 +msgid "Failed to write encrypted file: {0}" +msgstr "" + +#: src/constants/errors/backup.ts:31 +msgid "Failed to write to zip buffer: {0}" +msgstr "" + #: src/language/constants.ts:32 msgid "File exists" msgstr "檔案已存在" @@ -1081,7 +1343,7 @@ msgstr "檔名空白" msgid "Filter" msgstr "篩選" -#: src/language/constants.ts:19 src/views/site/SiteAdd.vue:97 +#: src/language/constants.ts:19 src/views/site/site_add/SiteAdd.vue:97 msgid "Finished" msgstr "完成" @@ -1153,11 +1415,15 @@ msgstr "正在取得憑證,請稍候..." msgid "Github Proxy" msgstr "Github 代理" +#: src/constants/errors/backup.ts:54 +msgid "Hash verification failed: file integrity compromised" +msgstr "" + #: src/components/SensitiveString/SensitiveString.vue:40 msgid "Hide" msgstr "隱藏" -#: src/routes/index.ts:30 +#: src/routes/index.ts:47 msgid "Home" msgstr "首頁" @@ -1207,7 +1473,8 @@ msgstr "如果您的域名有 CNAME 記錄且無法獲取證書,您需要啟 msgid "Import" msgstr "導入" -#: src/routes/index.ts:174 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:46 +#: src/views/certificate/CertificateEditor.vue:85 msgid "Import Certificate" msgstr "導入憑證" @@ -1232,7 +1499,7 @@ msgstr "請輸入應用程式中的代碼:" msgid "Input the recovery code:" msgstr "輸入恢復碼:" -#: src/routes/index.ts:312 src/views/other/Install.vue:134 +#: src/routes/modules/auth.ts:8 src/views/other/Install.vue:134 msgid "Install" msgstr "安裝" @@ -1248,6 +1515,21 @@ msgstr "間隔" msgid "Invalid" msgstr "無效" +#: src/constants/errors/backup.ts:42 +#, fuzzy +msgid "Invalid AES IV format: {0}" +msgstr "無效的請求格式" + +#: src/constants/errors/backup.ts:41 +#, fuzzy +msgid "Invalid AES key format: {0}" +msgstr "無效的請求格式" + +#: src/views/system/Backup/SystemRestore.vue:67 +#, fuzzy +msgid "Invalid file object" +msgstr "無效的檔案名" + #: src/views/config/components/Rename.vue:64 #: src/views/config/ConfigEditor.vue:250 msgid "Invalid filename" @@ -1261,6 +1543,10 @@ msgstr "無效的資料夾名稱" msgid "Invalid otp code" msgstr "無效的 OTP 代碼" +#: src/constants/errors/backup.ts:25 +msgid "Invalid padding in decrypted data" +msgstr "" + #: src/components/TwoFA/use2FAModal.ts:61 msgid "Invalid passcode or recovery code" msgstr "無效的密碼或恢復碼" @@ -1273,6 +1559,11 @@ msgstr "無效的恢復碼" msgid "Invalid request format" msgstr "無效的請求格式" +#: src/constants/errors/backup.ts:40 +#, fuzzy +msgid "Invalid security token format" +msgstr "無效的請求格式" + #: src/views/preference/AuthSettings.vue:18 msgid "IP" msgstr "IP" @@ -1388,7 +1679,7 @@ msgstr "Locations" msgid "Log" msgstr "日誌" -#: src/routes/index.ts:318 src/views/other/Login.vue:222 +#: src/routes/modules/auth.ts:14 src/views/other/Login.vue:222 msgid "Login" msgstr "登入" @@ -1425,20 +1716,20 @@ msgid "" msgstr "" "在取得憑證前,請確保您已將 .well-known 目錄反向代理到 HTTPChallengePort。" -#: src/routes/index.ts:108 src/views/config/ConfigEditor.vue:102 +#: src/routes/modules/config.ts:10 src/views/config/ConfigEditor.vue:102 #: src/views/config/ConfigEditor.vue:139 src/views/config/ConfigList.vue:69 msgid "Manage Configs" msgstr "管理設定" -#: src/routes/index.ts:47 src/views/site/site_list/SiteList.vue:94 +#: src/routes/modules/sites.ts:10 src/views/site/site_list/SiteList.vue:94 msgid "Manage Sites" msgstr "管理網站" -#: src/routes/index.ts:89 src/views/stream/StreamList.vue:119 +#: src/routes/modules/streams.ts:10 src/views/stream/StreamList.vue:119 msgid "Manage Streams" msgstr "管理 Stream" -#: src/routes/index.ts:257 src/views/user/User.vue:10 +#: src/routes/modules/user.ts:10 src/views/user/User.vue:10 msgid "Manage Users" msgstr "管理使用者" @@ -1474,11 +1765,12 @@ msgstr "模型" msgid "Modify" msgstr "修改" -#: src/routes/index.ts:164 src/views/certificate/CertificateEditor.vue:85 +#: src/routes/modules/certificates.ts:36 +#: src/views/certificate/CertificateEditor.vue:85 msgid "Modify Certificate" msgstr "修改憑證" -#: src/views/site/SiteAdd.vue:154 +#: src/views/site/site_add/SiteAdd.vue:154 msgid "Modify Config" msgstr "修改設定" @@ -1539,7 +1831,7 @@ msgstr "新版本發布" #: src/views/certificate/WildcardCertificate.vue:91 #: src/views/site/cert/components/ObtainCert.vue:211 -#: src/views/site/SiteAdd.vue:141 +#: src/views/site/site_add/SiteAdd.vue:141 msgid "Next" msgstr "下一步" @@ -1575,6 +1867,16 @@ msgstr "Nginx 配置檔未包含 sites-enabled" msgid "Nginx conf not include stream-enabled" msgstr "Nginx 配置檔未包含 stream-enabled" +#: src/constants/errors/backup.ts:18 +#, fuzzy +msgid "Nginx config directory is not set" +msgstr "Nginx 日誌目錄白名單" + +#: src/views/system/Backup/SystemRestore.vue:84 +#, fuzzy +msgid "Nginx configuration has been restored" +msgstr "Nginx 設定解析錯誤" + #: src/views/site/site_edit/SiteEdit.vue:223 #: src/views/stream/StreamEdit.vue:208 msgid "Nginx Configuration Parse Error" @@ -1596,7 +1898,7 @@ msgstr "Nginx 錯誤日誌路徑" msgid "Nginx is not running" msgstr "Nginx 未執行" -#: src/routes/index.ts:202 src/views/nginx_log/NginxLog.vue:148 +#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:148 msgid "Nginx Log" msgstr "Nginx 日誌" @@ -1624,6 +1926,18 @@ msgstr "Nginx 重啟指令" msgid "Nginx restarted successfully" msgstr "Nginx 重啟成功" +#: src/views/system/Backup/SystemRestore.vue:88 +#, fuzzy +msgid "Nginx UI configuration has been restored" +msgstr "Nginx 設定解析錯誤" + +#: src/views/system/Backup/SystemRestore.vue:93 +#, fuzzy +msgid "" +"Nginx UI configuration has been restored and will restart automatically in a " +"few seconds." +msgstr "Nginx 設定解析錯誤" + #: src/components/ChatGPT/ChatGPT.vue:374 #: src/components/Notification/Notification.vue:133 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:63 @@ -1653,7 +1967,7 @@ msgstr "節點密鑰" msgid "Not After" msgstr "不晚於" -#: src/routes/index.ts:324 +#: src/routes/modules/error.ts:8 msgid "Not Found" msgstr "找不到頁面" @@ -1676,7 +1990,8 @@ msgstr "請注意,如果配置檔包含其他配置或憑證,請提前將它 msgid "Notification" msgstr "通知" -#: src/components/Notification/Notification.vue:131 src/routes/index.ts:248 +#: src/components/Notification/Notification.vue:131 +#: src/routes/modules/notifications.ts:10 msgid "Notifications" msgstr "通知" @@ -1724,6 +2039,8 @@ msgstr "確定" #: src/views/site/site_list/SiteList.vue:144 #: src/views/stream/components/RightSettings.vue:50 #: src/views/stream/StreamList.vue:164 +#: src/views/system/Backup/BackupCreator.vue:149 +#: src/views/system/Backup/SystemRestore.vue:94 msgid "OK" msgstr "確定" @@ -1738,6 +2055,10 @@ msgstr "驗證完成後,記錄將被刪除。" msgid "Online" msgstr "線上" +#: src/views/system/Backup/SystemRestore.vue:24 +msgid "Only zip files are allowed" +msgstr "" + #: src/views/preference/Preference.vue:170 msgid "OpenAI" msgstr "OpenAI" @@ -1847,6 +2168,15 @@ msgstr "請輸入您希望創建的通行密鑰名稱,並點擊下面的確定 msgid "Please enter the OTP code:" msgstr "請輸入 OTP 代碼:" +#: src/views/system/Backup/SystemRestore.vue:58 +#, fuzzy +msgid "Please enter the security token" +msgstr "請輸入 OTP 代碼:" + +#: src/views/system/Backup/SystemRestore.vue:153 +msgid "Please enter the security token received during backup" +msgstr "" + #: src/views/certificate/DNSCredential.vue:53 msgid "" "Please fill in the API authentication credentials provided by your DNS " @@ -1910,6 +2240,15 @@ msgid "" "Please note that the unit of time configurations below are all in seconds." msgstr "請注意,以下時間配置單位均為秒。" +#: src/views/system/Backup/BackupCreator.vue:107 +msgid "Please save this security token, you will need it for restoration:" +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:53 +#, fuzzy +msgid "Please select a backup file" +msgstr "請至少選擇一個節點!" + #: src/views/environment/Environment.vue:58 msgid "Please select at least one node to upgrade" msgstr "請至少選擇一個節點進行升級" @@ -1920,7 +2259,7 @@ msgstr "請至少選擇一個節點進行升級" msgid "Pre-release" msgstr "預先發布" -#: src/routes/index.ts:266 src/views/preference/Preference.vue:141 +#: src/routes/modules/preference.ts:10 src/views/preference/Preference.vue:141 msgid "Preference" msgstr "偏好設定" @@ -2182,6 +2521,21 @@ msgstr "重新啟動" msgid "Restarting" msgstr "正在重新啟動" +#: src/views/system/Backup/SystemRestore.vue:81 +#, fuzzy +msgid "Restore completed successfully" +msgstr "刪除成功" + +#: src/views/system/Backup/SystemRestore.vue:165 +#, fuzzy +msgid "Restore Nginx Configuration" +msgstr "Nginx 配置目錄" + +#: src/views/system/Backup/SystemRestore.vue:176 +#, fuzzy +msgid "Restore Nginx UI Configuration" +msgstr "Nginx 配置目錄" + #: src/views/preference/AuthSettings.vue:107 msgid "RP Display Name" msgstr "RP 顯示名稱" @@ -2224,7 +2578,7 @@ msgstr "儲存指令" #: src/views/config/ConfigEditor.vue:171 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:41 -#: src/views/site/SiteAdd.vue:46 +#: src/views/site/site_add/SiteAdd.vue:46 msgid "Save error %{msg}" msgstr "儲存錯誤 %{msg}" @@ -2275,7 +2629,8 @@ msgstr "儲存成功" #: src/views/config/ConfigEditor.vue:167 #: src/views/site/ngx_conf/directive/DirectiveEditorItem.vue:39 -#: src/views/site/site_edit/SiteEdit.vue:152 src/views/site/SiteAdd.vue:37 +#: src/views/site/site_add/SiteAdd.vue:37 +#: src/views/site/site_edit/SiteEdit.vue:152 #: src/views/stream/StreamEdit.vue:139 msgid "Saved successfully" msgstr "儲存成功" @@ -2292,11 +2647,20 @@ msgstr "SDK" msgid "Secret has been copied" msgstr "密鑰已複製" +#: src/views/system/Backup/SystemRestore.vue:150 +msgid "Security Token" +msgstr "" + +#: src/views/system/Backup/BackupCreator.vue:94 +#, fuzzy +msgid "Security Token Information" +msgstr "無效的請求格式" + #: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:189 msgid "Selector" msgstr "選擇器" -#: src/routes/index.ts:283 src/views/system/SelfCheck/SelfCheck.vue:42 +#: src/routes/modules/system.ts:19 src/views/system/SelfCheck/SelfCheck.vue:42 msgid "Self Check" msgstr "自我檢測" @@ -2367,11 +2731,12 @@ msgstr "使用通行密鑰登入" msgid "Single Directive" msgstr "單一指令" -#: src/routes/index.ts:71 src/views/site/site_category/SiteCategory.vue:10 +#: src/routes/modules/sites.ts:34 +#: src/views/site/site_category/SiteCategory.vue:10 msgid "Site Categories" msgstr "網站類別" -#: src/views/site/SiteAdd.vue:147 +#: src/views/site/site_add/SiteAdd.vue:147 #, fuzzy msgid "Site Config Created Successfully" msgstr "網域設定檔成功建立" @@ -2380,7 +2745,7 @@ msgstr "網域設定檔成功建立" msgid "Site is enabled" msgstr "站點已啓用" -#: src/routes/index.ts:224 +#: src/routes/modules/nginx_log.ts:31 msgid "Site Logs" msgstr "網站日誌" @@ -2392,7 +2757,7 @@ msgstr "站點未找到" msgid "Sites Directory" msgstr "Sites 資料夾" -#: src/routes/index.ts:56 +#: src/routes/modules/sites.ts:19 msgid "Sites List" msgstr "網站列表" @@ -2430,6 +2795,10 @@ msgstr "SSO 登錄" msgid "Stable" msgstr "穩定" +#: src/views/system/Backup/SystemRestore.vue:187 +msgid "Start Restore" +msgstr "" + #: src/views/certificate/ACMEUser.vue:65 #: src/views/certificate/CertificateList/certColumns.tsx:68 #: src/views/environment/envColumns.tsx:44 @@ -2483,6 +2852,10 @@ msgstr "" "理使用,請參考此鏈接編寫對應的配置文件: https://nginxui.com/guide/nginx-" "proxy-example.html" +#: src/views/system/Backup/SystemRestore.vue:140 +msgid "Supported file type: .zip" +msgstr "" + #: src/views/dashboard/ServerAnalytic.vue:236 #: src/views/dashboard/ServerAnalytic.vue:237 msgid "Swap" @@ -2540,7 +2913,7 @@ msgstr "同步配置錯誤" msgid "Sync Config Success" msgstr "同步配置成功" -#: src/views/site/site_category/SiteCategory.vue:17 +#: src/views/site/site_category/SiteCategory.vue:18 msgid "Sync Nodes" msgstr "同步節點" @@ -2557,19 +2930,29 @@ msgstr "同步到" msgid "Synchronization" msgstr "同步" -#: src/routes/index.ts:275 +#: src/routes/modules/system.ts:11 msgid "System" msgstr "系統" +#: src/views/system/Backup/BackupCreator.vue:71 +#, fuzzy +msgid "System Backup" +msgstr "系統" + #: src/views/certificate/ACMEUserSelector.vue:88 msgid "System Initial User" msgstr "系統初始使用者" +#: src/views/system/Backup/SystemRestore.vue:117 +#, fuzzy +msgid "System Restore" +msgstr "系統" + #: src/constants/errors/self_check.ts:2 msgid "Task not found" msgstr "找不到任務" -#: src/routes/index.ts:194 src/views/terminal/Terminal.vue:114 +#: src/routes/modules/terminal.ts:10 src/views/terminal/Terminal.vue:114 msgid "Terminal" msgstr "終端機" @@ -2621,7 +3004,7 @@ msgid "" "dashes, colons, and dots." msgstr "節點名稱僅能包含字母、Unicode 字元、數字、連字號、破折號、冒號和句點。" -#: src/views/site/SiteAdd.vue:120 +#: src/views/site/site_add/SiteAdd.vue:120 #, fuzzy msgid "The parameter of server_name is required" msgstr "必須提供 server_name 參數" @@ -2710,10 +3093,28 @@ msgid "" "This field should only contain letters, unicode characters, numbers, and -_." msgstr "此欄位僅能包含字母、Unicode字元、數字、連字號、破折號和底線。" +#: src/views/system/Backup/BackupCreator.vue:141 +msgid "" +"This token will only be shown once and cannot be retrieved later. Please " +"make sure to save it in a secure location." +msgstr "" + #: src/constants/form_errors.ts:4 msgid "This value is already taken" msgstr "此值已被使用" +#: src/views/system/Backup/SystemRestore.vue:169 +msgid "" +"This will restore all Nginx configuration files. Nginx will restart after " +"the restoration is complete." +msgstr "" + +#: src/views/system/Backup/SystemRestore.vue:180 +msgid "" +"This will restore configuration files and database. Nginx UI will restart " +"after the restoration is complete." +msgstr "" + #: src/views/environment/BatchUpgrader.vue:182 msgid "" "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}." @@ -2820,7 +3221,7 @@ msgstr "更新時間" msgid "Updated successfully" msgstr "更新成功" -#: src/routes/index.ts:297 src/views/environment/Environment.vue:66 +#: src/routes/modules/system.ts:40 src/views/environment/Environment.vue:66 #: src/views/system/Upgrade.vue:143 src/views/system/Upgrade.vue:226 msgid "Upgrade" msgstr "升級" @@ -2883,6 +3284,10 @@ msgstr "使用者名稱 (*)" msgid "Valid" msgstr "有效" +#: src/views/system/Backup/SystemRestore.vue:159 +msgid "Verify Backup File Integrity" +msgstr "" + #: src/views/environment/envColumns.tsx:31 msgid "Version" msgstr "版本" @@ -2915,10 +3320,18 @@ msgstr "已檢視" #: src/constants/index.ts:17 src/views/config/InspectConfig.vue:33 #: src/views/notification/notificationColumns.tsx:22 #: src/views/preference/components/AddPasskey.vue:82 -#: src/views/site/SiteAdd.vue:115 +#: src/views/site/site_add/SiteAdd.vue:115 +#: src/views/system/Backup/BackupCreator.vue:138 msgid "Warning" msgstr "警告" +#: src/views/system/Backup/SystemRestore.vue:121 +msgid "" +"Warning: Restore operation will overwrite current configurations. Make sure " +"you have a valid backup file and security token, and carefully select what " +"to restore." +msgstr "" + #: src/views/certificate/DNSCredential.vue:56 msgid "" "We will add one or more TXT records to the DNS records of your domain for " @@ -3022,6 +3435,10 @@ msgstr "您的舊代碼將不再有效。" msgid "Your passkeys" msgstr "您的通行密鑰" +#, fuzzy +#~ msgid "Restart Required" +#~ msgstr "正在重新啟動" + #~ msgid "Deploy %{conf_name} to %{node_name} successfully" #~ msgstr "成功部署 %{conf_name} 至 %{node_name}" @@ -3053,9 +3470,6 @@ msgstr "您的通行密鑰" #~ msgid "Enable successfully" #~ msgstr "啟用成功" -#~ msgid "Please select at least one node!" -#~ msgstr "請至少選擇一個節點!" - #~ msgid "Please upgrade the remote Nginx UI to the latest version" #~ msgstr "請將遠端 Nginx UI 升級至最新版本" diff --git a/app/src/lib/http/index.ts b/app/src/lib/http/index.ts index e745b903..c6c9010d 100644 --- a/app/src/lib/http/index.ts +++ b/app/src/lib/http/index.ts @@ -30,6 +30,19 @@ function registerError(scope: string, record: CosyErrorRecord) { errors[scope] = record } +export interface HttpConfig extends AxiosRequestConfig { + returnFullResponse?: boolean + crypto?: boolean +} + +// Extend InternalAxiosRequestConfig type +declare module 'axios' { + interface InternalAxiosRequestConfig { + returnFullResponse?: boolean + crypto?: boolean + } +} + const instance = axios.create({ baseURL: import.meta.env.VITE_API_ROOT, timeout: 50000, @@ -37,25 +50,25 @@ const instance = axios.create({ }) const http = { - get(url: string, config: AxiosRequestConfig = {}) { + get(url: string, config: HttpConfig = {}) { // eslint-disable-next-line ts/no-explicit-any return instance.get(url, config) }, // eslint-disable-next-line ts/no-explicit-any - post(url: string, data: any = undefined, config: AxiosRequestConfig = {}) { + post(url: string, data: any = undefined, config: HttpConfig = {}) { // eslint-disable-next-line ts/no-explicit-any return instance.post(url, data, config) }, // eslint-disable-next-line ts/no-explicit-any - put(url: string, data: any = undefined, config: AxiosRequestConfig = {}) { + put(url: string, data: any = undefined, config: HttpConfig = {}) { // eslint-disable-next-line ts/no-explicit-any return instance.put(url, data, config) }, - delete(url: string, config: AxiosRequestConfig = {}) { + delete(url: string, config: HttpConfig = {}) { // eslint-disable-next-line ts/no-explicit-any return instance.delete(url, config) }, - patch(url: string, config: AxiosRequestConfig = {}) { + patch(url: string, config: HttpConfig = {}) { // eslint-disable-next-line ts/no-explicit-any return instance.patch(url, config) }, @@ -127,6 +140,10 @@ const dedupe = useMessageDedupe() instance.interceptors.response.use( response => { nprogress.done() + // Check if full response is requested in config + if (response.config?.returnFullResponse) { + return Promise.resolve(response) + } return Promise.resolve(response.data) }, // eslint-disable-next-line sonarjs/cognitive-complexity @@ -144,6 +161,18 @@ instance.interceptors.response.use( break } + // Handle JSON error that comes back as Blob for blob request type + if (error.response.data instanceof Blob && error.response.data.type === 'application/json') { + try { + const text = await error.response.data.text() + error.response.data = JSON.parse(text) + } + catch (e) { + // If parsing fails, we'll continue with the original error.response.data + console.error('Failed to parse blob error response as JSON', e) + } + } + const err = error.response.data as CosyError if (err?.scope) { diff --git a/app/src/routes/index.ts b/app/src/routes/index.ts index 3ed2db4a..e8f9670a 100644 --- a/app/src/routes/index.ts +++ b/app/src/routes/index.ts @@ -1,25 +1,42 @@ import type { RouteRecordRaw } from 'vue-router' import { useNProgress } from '@/lib/nprogress/nprogress' - -import { useSettingsStore, useUserStore } from '@/pinia' -import { - BellOutlined, - CloudOutlined, - CodeOutlined, - DatabaseOutlined, - FileOutlined, - FileTextOutlined, - HomeOutlined, - InfoCircleOutlined, - SafetyCertificateOutlined, - SettingOutlined, - ShareAltOutlined, - UserOutlined, -} from '@ant-design/icons-vue' - +import { useUserStore } from '@/pinia' import { createRouter, createWebHashHistory } from 'vue-router' +import { authRoutes } from './modules/auth' + +import { certificatesRoutes } from './modules/certificates' +import { configRoutes } from './modules/config' +// Import module routes +import { dashboardRoutes } from './modules/dashboard' +import { environmentsRoutes } from './modules/environments' +import { errorRoutes } from './modules/error' +import { nginxLogRoutes } from './modules/nginx_log' +import { notificationsRoutes } from './modules/notifications' +import { preferenceRoutes } from './modules/preference' +import { sitesRoutes } from './modules/sites' +import { streamsRoutes } from './modules/streams' +import { systemRoutes } from './modules/system' +import { terminalRoutes } from './modules/terminal' +import { userRoutes } from './modules/user' import 'nprogress/nprogress.css' +// Combine child routes for the main layout +const mainLayoutChildren: RouteRecordRaw[] = [ + ...dashboardRoutes, + ...sitesRoutes, + ...streamsRoutes, + ...configRoutes, + ...certificatesRoutes, + ...terminalRoutes, + ...nginxLogRoutes, + ...environmentsRoutes, + ...notificationsRoutes, + ...userRoutes, + ...preferenceRoutes, + ...systemRoutes, +] + +// Main routes configuration export const routes: RouteRecordRaw[] = [ { path: '/', @@ -29,300 +46,10 @@ export const routes: RouteRecordRaw[] = [ meta: { name: () => $gettext('Home'), }, - children: [ - { - path: 'dashboard', - component: () => import('@/views/dashboard/DashBoard.vue'), - name: 'Dashboard', - meta: { - name: () => $gettext('Dashboard'), - icon: HomeOutlined, - }, - }, - { - path: 'sites', - name: 'Manage Sites', - component: () => import('@/layouts/BaseRouterView.vue'), - meta: { - name: () => $gettext('Manage Sites'), - icon: CloudOutlined, - }, - redirect: '/sites/list', - children: [{ - path: 'list', - name: 'Sites List', - component: () => import('@/views/site/site_list/SiteList.vue'), - meta: { - name: () => $gettext('Sites List'), - }, - }, { - path: 'add', - name: 'Add Site', - component: () => import('@/views/site/site_add/SiteAdd.vue'), - meta: { - name: () => $gettext('Add Site'), - lastRouteName: 'Sites List', - }, - }, { - path: 'categories', - name: 'Site Categories', - component: () => import('@/views/site/site_category/SiteCategory.vue'), - meta: { - name: () => $gettext('Site Categories'), - }, - }, { - path: ':name', - name: 'Edit Site', - component: () => import('@/views/site/site_edit/SiteEdit.vue'), - meta: { - name: () => $gettext('Edit Site'), - hiddenInSidebar: true, - lastRouteName: 'Sites List', - }, - }], - }, - { - path: 'streams', - name: 'Manage Streams', - component: () => import('@/views/stream/StreamList.vue'), - meta: { - name: () => $gettext('Manage Streams'), - icon: ShareAltOutlined, - }, - }, - { - path: 'streams/:name', - name: 'Edit Stream', - component: () => import('@/views/stream/StreamEdit.vue'), - meta: { - name: () => $gettext('Edit Stream'), - hiddenInSidebar: true, - lastRouteName: 'Manage Streams', - }, - }, - { - path: 'config', - name: 'Manage Configs', - component: () => import('@/views/config/ConfigList.vue'), - meta: { - name: () => $gettext('Manage Configs'), - icon: FileOutlined, - hideChildren: true, - }, - }, - { - path: 'config/add', - name: 'Add Configuration', - component: () => import('@/views/config/ConfigEditor.vue'), - meta: { - name: () => $gettext('Add Configuration'), - hiddenInSidebar: true, - lastRouteName: 'Manage Configs', - }, - }, - { - path: 'config/:name+/edit', - name: 'Edit Configuration', - component: () => import('@/views/config/ConfigEditor.vue'), - meta: { - name: () => $gettext('Edit Configuration'), - hiddenInSidebar: true, - lastRouteName: 'Manage Configs', - }, - }, - { - path: 'certificates', - name: 'Certificates', - component: () => import('@/layouts/BaseRouterView.vue'), - redirect: '/certificates/list', - meta: { - name: () => $gettext('Certificates'), - icon: SafetyCertificateOutlined, - }, - children: [ - { - path: 'acme_users', - name: 'ACME User', - component: () => import('@/views/certificate/ACMEUser.vue'), - meta: { - name: () => $gettext('ACME User'), - }, - }, - { - path: 'list', - name: 'Certificates List', - component: () => import('@/views/certificate/CertificateList/Certificate.vue'), - meta: { - name: () => $gettext('Certificates List'), - }, - }, - { - path: ':id', - name: 'Modify Certificate', - component: () => import('@/views/certificate/CertificateEditor.vue'), - meta: { - name: () => $gettext('Modify Certificate'), - hiddenInSidebar: true, - lastRouteName: 'Certificates List', - }, - }, - { - path: 'import', - name: 'Import Certificate', - component: () => import('@/views/certificate/CertificateEditor.vue'), - meta: { - name: () => $gettext('Import Certificate'), - hiddenInSidebar: true, - lastRouteName: 'Certificates List', - }, - }, - { - path: 'dns_credential', - name: 'DNS Credentials', - component: () => import('@/views/certificate/DNSCredential.vue'), - meta: { - name: () => $gettext('DNS Credentials'), - }, - }, - ], - }, - { - path: 'terminal', - name: 'Terminal', - component: () => import('@/views/terminal/Terminal.vue'), - meta: { - name: () => $gettext('Terminal'), - icon: CodeOutlined, - }, - }, - { - path: 'nginx_log', - name: 'Nginx Log', - meta: { - name: () => $gettext('Nginx Log'), - icon: FileTextOutlined, - }, - children: [{ - path: 'access', - name: 'Access Logs', - component: () => import('@/views/nginx_log/NginxLog.vue'), - meta: { - name: () => $gettext('Access Logs'), - }, - }, { - path: 'error', - name: 'Error Logs', - component: () => import('@/views/nginx_log/NginxLog.vue'), - meta: { - name: () => $gettext('Error Logs'), - }, - }, { - path: 'site', - name: 'Site Logs', - component: () => import('@/views/nginx_log/NginxLog.vue'), - meta: { - name: () => $gettext('Site Logs'), - hiddenInSidebar: true, - }, - }], - }, - { - path: 'environments', - name: 'Environments', - component: () => import('@/views/environment/Environment.vue'), - meta: { - name: () => $gettext('Environments'), - icon: DatabaseOutlined, - hiddenInSidebar: (): boolean => { - const settings = useSettingsStore() - - return settings.is_remote - }, - }, - }, - { - path: 'notifications', - name: 'Notifications', - component: () => import('@/views/notification/Notification.vue'), - meta: { - name: () => $gettext('Notifications'), - icon: BellOutlined, - }, - }, - { - path: 'user', - name: 'Manage Users', - component: () => import('@/views/user/User.vue'), - meta: { - name: () => $gettext('Manage Users'), - icon: UserOutlined, - }, - }, - { - path: 'preference', - name: 'Preference', - component: () => import('@/views/preference/Preference.vue'), - meta: { - name: () => $gettext('Preference'), - icon: SettingOutlined, - }, - }, - { - path: 'system', - name: 'System', - redirect: 'system/about', - meta: { - name: () => $gettext('System'), - icon: InfoCircleOutlined, - }, - children: [{ - path: 'self_check', - name: 'Self Check', - component: () => import('@/views/system/SelfCheck/SelfCheck.vue'), - meta: { - name: () => $gettext('Self Check'), - }, - }, { - path: 'about', - name: 'About', - component: () => import('@/views/system/About.vue'), - meta: { - name: () => $gettext('About'), - }, - }, { - path: 'upgrade', - name: 'Upgrade', - component: () => import('@/views/system/Upgrade.vue'), - meta: { - name: () => $gettext('Upgrade'), - hiddenInSidebar: (): boolean => { - const settings = useSettingsStore() - - return settings.is_remote - }, - }, - }], - }, - ], - }, - { - path: '/install', - name: 'Install', - component: () => import('@/views/other/Install.vue'), - meta: { name: () => $gettext('Install'), noAuth: true }, - }, - { - path: '/login', - name: 'Login', - component: () => import('@/views/other/Login.vue'), - meta: { name: () => $gettext('Login'), noAuth: true }, - }, - { - path: '/:pathMatch(.*)*', - name: 'Not Found', - component: () => import('@/views/other/Error.vue'), - meta: { name: () => $gettext('Not Found'), noAuth: true, status_code: 404, error: () => $gettext('Not Found') }, + children: mainLayoutChildren, }, + ...authRoutes, + ...errorRoutes, ] const router = createRouter({ diff --git a/app/src/routes/modules/auth.ts b/app/src/routes/modules/auth.ts new file mode 100644 index 00000000..3290f6b6 --- /dev/null +++ b/app/src/routes/modules/auth.ts @@ -0,0 +1,16 @@ +import type { RouteRecordRaw } from 'vue-router' + +export const authRoutes: RouteRecordRaw[] = [ + { + path: '/install', + name: 'Install', + component: () => import('@/views/other/Install.vue'), + meta: { name: () => $gettext('Install'), noAuth: true }, + }, + { + path: '/login', + name: 'Login', + component: () => import('@/views/other/Login.vue'), + meta: { name: () => $gettext('Login'), noAuth: true }, + }, +] diff --git a/app/src/routes/modules/certificates.ts b/app/src/routes/modules/certificates.ts new file mode 100644 index 00000000..fc22b361 --- /dev/null +++ b/app/src/routes/modules/certificates.ts @@ -0,0 +1,61 @@ +import type { RouteRecordRaw } from 'vue-router' +import { SafetyCertificateOutlined } from '@ant-design/icons-vue' + +export const certificatesRoutes: RouteRecordRaw[] = [ + { + path: 'certificates', + name: 'Certificates', + component: () => import('@/layouts/BaseRouterView.vue'), + redirect: '/certificates/list', + meta: { + name: () => $gettext('Certificates'), + icon: SafetyCertificateOutlined, + }, + children: [ + { + path: 'acme_users', + name: 'ACME User', + component: () => import('@/views/certificate/ACMEUser.vue'), + meta: { + name: () => $gettext('ACME User'), + }, + }, + { + path: 'list', + name: 'Certificates List', + component: () => import('@/views/certificate/CertificateList/Certificate.vue'), + meta: { + name: () => $gettext('Certificates List'), + }, + }, + { + path: ':id', + name: 'Modify Certificate', + component: () => import('@/views/certificate/CertificateEditor.vue'), + meta: { + name: () => $gettext('Modify Certificate'), + hiddenInSidebar: true, + lastRouteName: 'Certificates List', + }, + }, + { + path: 'import', + name: 'Import Certificate', + component: () => import('@/views/certificate/CertificateEditor.vue'), + meta: { + name: () => $gettext('Import Certificate'), + hiddenInSidebar: true, + lastRouteName: 'Certificates List', + }, + }, + { + path: 'dns_credential', + name: 'DNS Credentials', + component: () => import('@/views/certificate/DNSCredential.vue'), + meta: { + name: () => $gettext('DNS Credentials'), + }, + }, + ], + }, +] diff --git a/app/src/routes/modules/config.ts b/app/src/routes/modules/config.ts new file mode 100644 index 00000000..e1ad31ea --- /dev/null +++ b/app/src/routes/modules/config.ts @@ -0,0 +1,35 @@ +import type { RouteRecordRaw } from 'vue-router' +import { FileOutlined } from '@ant-design/icons-vue' + +export const configRoutes: RouteRecordRaw[] = [ + { + path: 'config', + name: 'Manage Configs', + component: () => import('@/views/config/ConfigList.vue'), + meta: { + name: () => $gettext('Manage Configs'), + icon: FileOutlined, + hideChildren: true, + }, + }, + { + path: 'config/add', + name: 'Add Configuration', + component: () => import('@/views/config/ConfigEditor.vue'), + meta: { + name: () => $gettext('Add Configuration'), + hiddenInSidebar: true, + lastRouteName: 'Manage Configs', + }, + }, + { + path: 'config/:name+/edit', + name: 'Edit Configuration', + component: () => import('@/views/config/ConfigEditor.vue'), + meta: { + name: () => $gettext('Edit Configuration'), + hiddenInSidebar: true, + lastRouteName: 'Manage Configs', + }, + }, +] diff --git a/app/src/routes/modules/dashboard.ts b/app/src/routes/modules/dashboard.ts new file mode 100644 index 00000000..dea2d42d --- /dev/null +++ b/app/src/routes/modules/dashboard.ts @@ -0,0 +1,14 @@ +import type { RouteRecordRaw } from 'vue-router' +import { HomeOutlined } from '@ant-design/icons-vue' + +export const dashboardRoutes: RouteRecordRaw[] = [ + { + path: 'dashboard', + component: () => import('@/views/dashboard/DashBoard.vue'), + name: 'Dashboard', + meta: { + name: () => $gettext('Dashboard'), + icon: HomeOutlined, + }, + }, +] diff --git a/app/src/routes/modules/environments.ts b/app/src/routes/modules/environments.ts new file mode 100644 index 00000000..e9c9efd2 --- /dev/null +++ b/app/src/routes/modules/environments.ts @@ -0,0 +1,20 @@ +import type { RouteRecordRaw } from 'vue-router' +import { useSettingsStore } from '@/pinia' +import { DatabaseOutlined } from '@ant-design/icons-vue' + +export const environmentsRoutes: RouteRecordRaw[] = [ + { + path: 'environments', + name: 'Environments', + component: () => import('@/views/environment/Environment.vue'), + meta: { + name: () => $gettext('Environments'), + icon: DatabaseOutlined, + hiddenInSidebar: (): boolean => { + const settings = useSettingsStore() + + return settings.is_remote + }, + }, + }, +] diff --git a/app/src/routes/modules/error.ts b/app/src/routes/modules/error.ts new file mode 100644 index 00000000..dbf2e74a --- /dev/null +++ b/app/src/routes/modules/error.ts @@ -0,0 +1,10 @@ +import type { RouteRecordRaw } from 'vue-router' + +export const errorRoutes: RouteRecordRaw[] = [ + { + path: '/:pathMatch(.*)*', + name: 'Not Found', + component: () => import('@/views/other/Error.vue'), + meta: { name: () => $gettext('Not Found'), noAuth: true, status_code: 404, error: () => $gettext('Not Found') }, + }, +] diff --git a/app/src/routes/modules/nginx_log.ts b/app/src/routes/modules/nginx_log.ts new file mode 100644 index 00000000..63f9d89b --- /dev/null +++ b/app/src/routes/modules/nginx_log.ts @@ -0,0 +1,36 @@ +import type { RouteRecordRaw } from 'vue-router' +import { FileTextOutlined } from '@ant-design/icons-vue' + +export const nginxLogRoutes: RouteRecordRaw[] = [ + { + path: 'nginx_log', + name: 'Nginx Log', + meta: { + name: () => $gettext('Nginx Log'), + icon: FileTextOutlined, + }, + children: [{ + path: 'access', + name: 'Access Logs', + component: () => import('@/views/nginx_log/NginxLog.vue'), + meta: { + name: () => $gettext('Access Logs'), + }, + }, { + path: 'error', + name: 'Error Logs', + component: () => import('@/views/nginx_log/NginxLog.vue'), + meta: { + name: () => $gettext('Error Logs'), + }, + }, { + path: 'site', + name: 'Site Logs', + component: () => import('@/views/nginx_log/NginxLog.vue'), + meta: { + name: () => $gettext('Site Logs'), + hiddenInSidebar: true, + }, + }], + }, +] diff --git a/app/src/routes/modules/notifications.ts b/app/src/routes/modules/notifications.ts new file mode 100644 index 00000000..e8ad7728 --- /dev/null +++ b/app/src/routes/modules/notifications.ts @@ -0,0 +1,14 @@ +import type { RouteRecordRaw } from 'vue-router' +import { BellOutlined } from '@ant-design/icons-vue' + +export const notificationsRoutes: RouteRecordRaw[] = [ + { + path: 'notifications', + name: 'Notifications', + component: () => import('@/views/notification/Notification.vue'), + meta: { + name: () => $gettext('Notifications'), + icon: BellOutlined, + }, + }, +] diff --git a/app/src/routes/modules/preference.ts b/app/src/routes/modules/preference.ts new file mode 100644 index 00000000..67ba443f --- /dev/null +++ b/app/src/routes/modules/preference.ts @@ -0,0 +1,14 @@ +import type { RouteRecordRaw } from 'vue-router' +import { SettingOutlined } from '@ant-design/icons-vue' + +export const preferenceRoutes: RouteRecordRaw[] = [ + { + path: 'preference', + name: 'Preference', + component: () => import('@/views/preference/Preference.vue'), + meta: { + name: () => $gettext('Preference'), + icon: SettingOutlined, + }, + }, +] diff --git a/app/src/routes/modules/sites.ts b/app/src/routes/modules/sites.ts new file mode 100644 index 00000000..8cf8a1e4 --- /dev/null +++ b/app/src/routes/modules/sites.ts @@ -0,0 +1,47 @@ +import type { RouteRecordRaw } from 'vue-router' +import { CloudOutlined } from '@ant-design/icons-vue' + +export const sitesRoutes: RouteRecordRaw[] = [ + { + path: 'sites', + name: 'Manage Sites', + component: () => import('@/layouts/BaseRouterView.vue'), + meta: { + name: () => $gettext('Manage Sites'), + icon: CloudOutlined, + }, + redirect: '/sites/list', + children: [{ + path: 'list', + name: 'Sites List', + component: () => import('@/views/site/site_list/SiteList.vue'), + meta: { + name: () => $gettext('Sites List'), + }, + }, { + path: 'add', + name: 'Add Site', + component: () => import('@/views/site/site_add/SiteAdd.vue'), + meta: { + name: () => $gettext('Add Site'), + lastRouteName: 'Sites List', + }, + }, { + path: 'categories', + name: 'Site Categories', + component: () => import('@/views/site/site_category/SiteCategory.vue'), + meta: { + name: () => $gettext('Site Categories'), + }, + }, { + path: ':name', + name: 'Edit Site', + component: () => import('@/views/site/site_edit/SiteEdit.vue'), + meta: { + name: () => $gettext('Edit Site'), + hiddenInSidebar: true, + lastRouteName: 'Sites List', + }, + }], + }, +] diff --git a/app/src/routes/modules/streams.ts b/app/src/routes/modules/streams.ts new file mode 100644 index 00000000..3ca4562b --- /dev/null +++ b/app/src/routes/modules/streams.ts @@ -0,0 +1,24 @@ +import type { RouteRecordRaw } from 'vue-router' +import { ShareAltOutlined } from '@ant-design/icons-vue' + +export const streamsRoutes: RouteRecordRaw[] = [ + { + path: 'streams', + name: 'Manage Streams', + component: () => import('@/views/stream/StreamList.vue'), + meta: { + name: () => $gettext('Manage Streams'), + icon: ShareAltOutlined, + }, + }, + { + path: 'streams/:name', + name: 'Edit Stream', + component: () => import('@/views/stream/StreamEdit.vue'), + meta: { + name: () => $gettext('Edit Stream'), + hiddenInSidebar: true, + lastRouteName: 'Manage Streams', + }, + }, +] diff --git a/app/src/routes/modules/system.ts b/app/src/routes/modules/system.ts new file mode 100644 index 00000000..ba020a57 --- /dev/null +++ b/app/src/routes/modules/system.ts @@ -0,0 +1,49 @@ +import type { RouteRecordRaw } from 'vue-router' +import { useSettingsStore } from '@/pinia' +import { InfoCircleOutlined } from '@ant-design/icons-vue' + +export const systemRoutes: RouteRecordRaw[] = [ + { + path: 'system', + name: 'System', + redirect: 'system/about', + meta: { + name: () => $gettext('System'), + icon: InfoCircleOutlined, + }, + children: [{ + path: 'self_check', + name: 'Self Check', + component: () => import('@/views/system/SelfCheck/SelfCheck.vue'), + meta: { + name: () => $gettext('Self Check'), + }, + }, { + path: 'about', + name: 'About', + component: () => import('@/views/system/About.vue'), + meta: { + name: () => $gettext('About'), + }, + }, { + path: 'backup', + name: 'Backup', + component: () => import('@/views/system/Backup/index.vue'), + meta: { + name: () => $gettext('Backup'), + }, + }, { + path: 'upgrade', + name: 'Upgrade', + component: () => import('@/views/system/Upgrade.vue'), + meta: { + name: () => $gettext('Upgrade'), + hiddenInSidebar: (): boolean => { + const settings = useSettingsStore() + + return settings.is_remote + }, + }, + }], + }, +] diff --git a/app/src/routes/modules/terminal.ts b/app/src/routes/modules/terminal.ts new file mode 100644 index 00000000..a1e341fb --- /dev/null +++ b/app/src/routes/modules/terminal.ts @@ -0,0 +1,14 @@ +import type { RouteRecordRaw } from 'vue-router' +import { CodeOutlined } from '@ant-design/icons-vue' + +export const terminalRoutes: RouteRecordRaw[] = [ + { + path: 'terminal', + name: 'Terminal', + component: () => import('@/views/terminal/Terminal.vue'), + meta: { + name: () => $gettext('Terminal'), + icon: CodeOutlined, + }, + }, +] diff --git a/app/src/routes/modules/user.ts b/app/src/routes/modules/user.ts new file mode 100644 index 00000000..f276a6c1 --- /dev/null +++ b/app/src/routes/modules/user.ts @@ -0,0 +1,14 @@ +import type { RouteRecordRaw } from 'vue-router' +import { UserOutlined } from '@ant-design/icons-vue' + +export const userRoutes: RouteRecordRaw[] = [ + { + path: 'user', + name: 'Manage Users', + component: () => import('@/views/user/User.vue'), + meta: { + name: () => $gettext('Manage Users'), + icon: UserOutlined, + }, + }, +] diff --git a/app/src/version.json b/app/src/version.json index 4feb865b..b7b0f496 100644 --- a/app/src/version.json +++ b/app/src/version.json @@ -1 +1 @@ -{"version":"2.0.0-rc.4","build_id":1,"total_build":386} \ No newline at end of file +{"version":"2.0.0-rc.4","build_id":2,"total_build":387} \ No newline at end of file diff --git a/app/src/views/system/Backup/BackupCreator.vue b/app/src/views/system/Backup/BackupCreator.vue new file mode 100644 index 00000000..75570b02 --- /dev/null +++ b/app/src/views/system/Backup/BackupCreator.vue @@ -0,0 +1,245 @@ + + + + + diff --git a/app/src/views/system/Backup/SystemRestore.vue b/app/src/views/system/Backup/SystemRestore.vue new file mode 100644 index 00000000..02ec3b9c --- /dev/null +++ b/app/src/views/system/Backup/SystemRestore.vue @@ -0,0 +1,192 @@ + + + diff --git a/app/src/views/system/Backup/index.vue b/app/src/views/system/Backup/index.vue new file mode 100644 index 00000000..688e5de4 --- /dev/null +++ b/app/src/views/system/Backup/index.vue @@ -0,0 +1,11 @@ + + + diff --git a/go.mod b/go.mod index 4ddeb6ff..e8b3083f 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/gin-gonic/gin v1.10.0 github.com/go-acme/lego/v4 v4.22.2 github.com/go-co-op/gocron/v2 v2.16.1 - github.com/go-playground/validator/v10 v10.25.0 + github.com/go-playground/validator/v10 v10.26.0 github.com/go-resty/resty/v2 v2.16.5 github.com/go-webauthn/webauthn v0.12.2 github.com/golang-jwt/jwt/v5 v5.2.2 @@ -34,12 +34,12 @@ require ( github.com/shirou/gopsutil/v4 v4.25.2 github.com/spf13/cast v1.7.1 github.com/stretchr/testify v1.10.0 - github.com/tufanbarisyildirim/gonginx v0.0.0-20250120210832-12a9c7ae0c8a - github.com/uozi-tech/cosy v1.16.0 + github.com/tufanbarisyildirim/gonginx v0.0.0-20250225174229-c03497ddaef6 + github.com/uozi-tech/cosy v1.17.0 github.com/uozi-tech/cosy-driver-sqlite v0.2.1 github.com/urfave/cli/v3 v3.0.0-beta1 golang.org/x/crypto v0.36.0 - golang.org/x/net v0.37.0 + golang.org/x/net v0.38.0 gopkg.in/ini.v1 v1.67.0 gorm.io/driver/sqlite v1.5.7 gorm.io/gen v0.3.26 @@ -49,13 +49,13 @@ require ( require ( aead.dev/minisign v0.3.0 // indirect - cloud.google.com/go/auth v0.14.1 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect + cloud.google.com/go/auth v0.15.0 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.6.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 // indirect github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 // indirect @@ -70,34 +70,34 @@ require ( github.com/Azure/go-autorest/autorest/to v0.4.1 // indirect github.com/Azure/go-autorest/logger v0.2.2 // indirect github.com/Azure/go-autorest/tracing v0.6.1 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.4.0 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect github.com/StackExchange/wmi v1.2.1 // indirect github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect - github.com/aliyun/alibaba-cloud-sdk-go v1.63.88 // indirect - github.com/aws/aws-sdk-go-v2 v1.36.2 // indirect - github.com/aws/aws-sdk-go-v2/config v1.29.7 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.60 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.29 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33 // indirect + github.com/aliyun/alibaba-cloud-sdk-go v1.63.103 // indirect + github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect + github.com/aws/aws-sdk-go-v2/config v1.29.12 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.65 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.14 // indirect - github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.16 // indirect - github.com/aws/aws-sdk-go-v2/service/route53 v1.48.8 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.24.16 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.15 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.33.15 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect + github.com/aws/aws-sdk-go-v2/service/lightsail v1.43.1 // indirect + github.com/aws/aws-sdk-go-v2/service/route53 v1.50.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.25.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 // indirect github.com/aws/smithy-go v1.22.3 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/boombuler/barcode v1.0.2 // indirect github.com/bsm/redislock v0.9.4 // indirect - github.com/bytedance/sonic v1.13.1 // indirect + github.com/bytedance/sonic v1.13.2 // indirect github.com/bytedance/sonic/loader v0.2.4 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/civo/civogo v0.3.94 // indirect + github.com/civo/civogo v0.3.96 // indirect github.com/cloudflare/cloudflare-go v0.115.0 // indirect github.com/cloudwego/base64x v0.1.5 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -105,7 +105,7 @@ require ( github.com/dimchansky/utfbom v1.1.1 // indirect github.com/dnsimple/dnsimple-go v1.7.0 // indirect github.com/ebitengine/purego v0.8.2 // indirect - github.com/exoscale/egoscale/v3 v3.1.9 // indirect + github.com/exoscale/egoscale/v3 v3.1.13 // indirect github.com/fatih/color v1.18.0 // indirect github.com/fatih/structs v1.1.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -115,25 +115,25 @@ require ( github.com/ghodss/yaml v1.0.0 // indirect github.com/gin-contrib/sse v1.0.0 // indirect github.com/go-errors/errors v1.5.1 // indirect - github.com/go-gormigrate/gormigrate/v2 v2.1.3 // indirect - github.com/go-jose/go-jose/v4 v4.0.4 // indirect + github.com/go-gormigrate/gormigrate/v2 v2.1.4 // indirect + github.com/go-jose/go-jose/v4 v4.0.5 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-sql-driver/mysql v1.9.0 // indirect + github.com/go-sql-driver/mysql v1.9.1 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/go-webauthn/x v0.1.19 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/gofrs/flock v0.12.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-jwt/jwt/v4 v4.5.1 // indirect + github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-tpm v0.9.3 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/s2a-go v0.1.9 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect github.com/googleapis/gax-go/v2 v2.14.1 // indirect github.com/gophercloud/gophercloud v1.14.1 // indirect github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 // indirect @@ -143,8 +143,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect - github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.136 // indirect + github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.142 // indirect github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect github.com/infobloxopen/infoblox-go-client v1.1.1 // indirect github.com/itchyny/timefmt-go v0.1.6 // indirect @@ -167,15 +166,14 @@ require ( github.com/labbsr0x/bindman-dns-webhook v1.0.2 // indirect github.com/labbsr0x/goh v1.0.1 // indirect github.com/leodido/go-urn v1.4.0 // indirect - github.com/linode/linodego v1.47.0 // indirect + github.com/linode/linodego v1.48.1 // indirect github.com/liquidweb/liquidweb-cli v0.7.0 // indirect github.com/liquidweb/liquidweb-go v1.6.4 // indirect - github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect - github.com/magiconair/properties v1.8.9 // indirect + github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.24 // indirect - github.com/miekg/dns v1.1.63 // indirect + github.com/miekg/dns v1.1.64 // indirect github.com/mimuret/golang-iij-dpf v0.9.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -183,8 +181,8 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect github.com/nrdcg/auroradns v1.1.0 // indirect - github.com/nrdcg/bunny-go v0.0.0-20240207213615-dde5bf4577a3 // indirect - github.com/nrdcg/desec v0.10.0 // indirect + github.com/nrdcg/bunny-go v0.0.0-20250327222614-988a091fc7ea // indirect + github.com/nrdcg/desec v0.11.0 // indirect github.com/nrdcg/dnspod-go v0.4.0 // indirect github.com/nrdcg/freemyip v0.3.0 // indirect github.com/nrdcg/goacmedns v0.2.0 // indirect @@ -196,7 +194,7 @@ require ( github.com/nxadm/tail v1.4.11 // indirect github.com/nzdjb/go-metaname v1.0.0 // indirect github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect - github.com/oracle/oci-go-sdk/v65 v65.83.2 // indirect + github.com/oracle/oci-go-sdk/v65 v65.88.0 // indirect github.com/ovh/go-ovh v1.7.0 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect @@ -211,9 +209,8 @@ require ( github.com/sacloud/go-http v0.1.9 // indirect github.com/sacloud/iaas-api-go v1.14.0 // indirect github.com/sacloud/packages-go v0.0.11 // indirect - github.com/sagikazarmark/locafero v0.7.0 // indirect - github.com/sagikazarmark/slog-shim v0.1.0 // indirect - github.com/scaleway/scaleway-sdk-go v1.0.0-beta.32 // indirect + github.com/sagikazarmark/locafero v0.9.0 // indirect + github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33 // indirect github.com/selectel/domains-go v1.1.0 // indirect github.com/selectel/go-selvpcclient/v3 v3.2.1 // indirect github.com/shopspring/decimal v1.4.0 // indirect @@ -224,15 +221,16 @@ require ( github.com/sony/gobreaker v1.0.0 // indirect github.com/sony/sonyflake v1.2.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.12.0 // indirect + github.com/spf13/afero v1.14.0 // indirect github.com/spf13/pflag v1.0.6 // indirect - github.com/spf13/viper v1.19.0 // indirect + github.com/spf13/viper v1.20.1 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1101 // indirect - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1101 // indirect + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1133 // indirect + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1128 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect - github.com/tklauser/go-sysconf v0.3.14 // indirect - github.com/tklauser/numcpus v0.9.0 // indirect + github.com/tklauser/go-sysconf v0.3.15 // indirect + github.com/tklauser/numcpus v0.10.0 // indirect github.com/transip/gotransip/v6 v6.26.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect @@ -240,39 +238,37 @@ require ( github.com/uozi-tech/cosy-driver-mysql v0.2.2 // indirect github.com/uozi-tech/cosy-driver-postgres v0.2.1 // indirect github.com/vinyldns/go-vinyldns v0.9.16 // indirect - github.com/volcengine/volc-sdk-golang v1.0.195 // indirect - github.com/vultr/govultr/v3 v3.14.1 // indirect + github.com/volcengine/volc-sdk-golang v1.0.201 // indirect + github.com/vultr/govultr/v3 v3.18.0 // indirect github.com/x448/float16 v0.8.4 // indirect - github.com/yandex-cloud/go-genproto v0.0.0-20250217111757-ccaea642a16c // indirect - github.com/yandex-cloud/go-sdk v0.0.0-20250210144447-399a857b9c4e // indirect + github.com/yandex-cloud/go-genproto v0.0.0-20250325081613-cd85d9003939 // indirect + github.com/yandex-cloud/go-sdk v0.0.0-20250325134853-dcb34ef70818 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - go.mongodb.org/mongo-driver v1.17.2 // indirect + go.mongodb.org/mongo-driver v1.17.3 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect - go.opentelemetry.io/otel v1.34.0 // indirect - go.opentelemetry.io/otel/metric v1.34.0 // indirect - go.opentelemetry.io/otel/trace v1.34.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect + go.opentelemetry.io/otel v1.35.0 // indirect + go.opentelemetry.io/otel/metric v1.35.0 // indirect + go.opentelemetry.io/otel/trace v1.35.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.3.1 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/arch v0.15.0 // indirect - golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect golang.org/x/mod v0.24.0 // indirect - golang.org/x/oauth2 v0.26.0 // indirect + golang.org/x/oauth2 v0.28.0 // indirect golang.org/x/sync v0.12.0 // indirect golang.org/x/sys v0.31.0 // indirect golang.org/x/text v0.23.0 // indirect - golang.org/x/time v0.10.0 // indirect + golang.org/x/time v0.11.0 // indirect golang.org/x/tools v0.31.0 // indirect - google.golang.org/api v0.221.0 // indirect - google.golang.org/genproto v0.0.0-20250218202821-56aae31c358a // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect - google.golang.org/grpc v1.70.0 // indirect - google.golang.org/protobuf v1.36.5 // indirect + google.golang.org/api v0.228.0 // indirect + google.golang.org/genproto v0.0.0-20250324211829-b45e905df463 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect + google.golang.org/grpc v1.71.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/fsnotify.v1 v1.4.7 // indirect - gopkg.in/guregu/null.v4 v4.0.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/ns1/ns1-go.v2 v2.13.0 // indirect @@ -283,11 +279,11 @@ require ( gorm.io/driver/mysql v1.5.7 // indirect gorm.io/driver/postgres v1.5.9 // indirect gorm.io/hints v1.1.2 // indirect - k8s.io/api v0.32.2 // indirect - k8s.io/apimachinery v0.32.2 // indirect + k8s.io/api v0.32.3 // indirect + k8s.io/apimachinery v0.32.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect + k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index be9f288e..b988b3b6 100644 --- a/go.sum +++ b/go.sum @@ -100,10 +100,10 @@ cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVo cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= -cloud.google.com/go/auth v0.14.1 h1:AwoJbzUdxA/whv1qj3TLKwh3XX5sikny2fc40wUl+h0= -cloud.google.com/go/auth v0.14.1/go.mod h1:4JHUxlGXisL0AW8kXPtUF6ztuOksyfUQNFjfsOCXkPM= -cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M= -cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc= +cloud.google.com/go/auth v0.15.0 h1:Ly0u4aA5vG/fsSsxu98qCQBemXtAtJf+95z9HK+cxps= +cloud.google.com/go/auth v0.15.0/go.mod h1:WJDGqZ1o9E9wKIL+IwStfyn/+s59zl4Bi+1KQNVXLZ8= +cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= +cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= @@ -612,8 +612,8 @@ github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 h1:Dy3M9aegiI7d7PF1LUdjbVigJReo+QOceYs github.com/AdamSLevy/jsonrpc2/v14 v14.1.0/go.mod h1:ZakZtbCXxCz82NJvq7MoREtiQesnDfrtF6RFUGzQfLo= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1 h1:DSDNVxqkoXJiko6x8a90zidoYqnYYa6c1MTzDKzKkTo= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1/go.mod h1:zGqV2R4Cr/k8Uye5w+dgQ06WJtEcbQG/8J7BB6hnCr4= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= @@ -660,12 +660,10 @@ github.com/Azure/go-autorest/tracing v0.6.1 h1:YUMSrC/CeD1ZnnXcNYU4a/fzsO35u2Fsf github.com/Azure/go-autorest/tracing v0.6.1/go.mod h1:/3EgjbsjraOqiicERAeu3m7/z0x1TzjQGAwDrJrXGkc= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= -github.com/AzureAD/microsoft-authentication-library-for-go v1.4.0 h1:MUkXAnvvDHgvPItl0nBj0hgk0f7hnnQbGm0h0+YxbN4= -github.com/AzureAD/microsoft-authentication-library-for-go v1.4.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs= +github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= -github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -698,8 +696,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/aliyun/alibaba-cloud-sdk-go v1.63.88 h1:87jNTxliGqU2yB3H09xCd4U3cZCmR4AkOMqWgaluo5Q= -github.com/aliyun/alibaba-cloud-sdk-go v1.63.88/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= +github.com/aliyun/alibaba-cloud-sdk-go v1.63.103 h1:kZsvZo6waUg5313S6VkoPx8QyyeoUfMgF/KgxpiEfCw= +github.com/aliyun/alibaba-cloud-sdk-go v1.63.103/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= @@ -714,35 +712,35 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= -github.com/aws/aws-sdk-go-v2 v1.36.2 h1:Ub6I4lq/71+tPb/atswvToaLGVMxKZvjYDVOWEExOcU= -github.com/aws/aws-sdk-go-v2 v1.36.2/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= -github.com/aws/aws-sdk-go-v2/config v1.29.7 h1:71nqi6gUbAUiEQkypHQcNVSFJVUFANpSeUNShiwWX2M= -github.com/aws/aws-sdk-go-v2/config v1.29.7/go.mod h1:yqJQ3nh2HWw/uxd56bicyvmDW4KSc+4wN6lL8pYjynU= -github.com/aws/aws-sdk-go-v2/credentials v1.17.60 h1:1dq+ELaT5ogfmqtV1eocq8SpOK1NRsuUfmhQtD/XAh4= -github.com/aws/aws-sdk-go-v2/credentials v1.17.60/go.mod h1:HDes+fn/xo9VeszXqjBVkxOo/aUy8Mc6QqKvZk32GlE= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.29 h1:JO8pydejFKmGcUNiiwt75dzLHRWthkwApIvPoyUtXEg= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.29/go.mod h1:adxZ9i9DRmB8zAT0pO0yGnsmu0geomp5a3uq5XpgOJ8= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33 h1:knLyPMw3r3JsU8MFHWctE4/e2qWbPaxDYLlohPvnY8c= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33/go.mod h1:EBp2HQ3f+XCB+5J+IoEbGhoV7CpJbnrsd4asNXmTL0A= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33 h1:K0+Ne08zqti8J9jwENxZ5NoUyBnaFDTu3apwQJWrwwA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33/go.mod h1:K97stwwzaWzmqxO8yLGHhClbVW1tC6VT1pDLk1pGrq4= +github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM= +github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= +github.com/aws/aws-sdk-go-v2/config v1.29.12 h1:Y/2a+jLPrPbHpFkpAAYkVEtJmxORlXoo5k2g1fa2sUo= +github.com/aws/aws-sdk-go-v2/config v1.29.12/go.mod h1:xse1YTjmORlb/6fhkWi8qJh3cvZi4JoVNhc+NbJt4kI= +github.com/aws/aws-sdk-go-v2/credentials v1.17.65 h1:q+nV2yYegofO/SUXruT+pn4KxkxmaQ++1B/QedcKBFM= +github.com/aws/aws-sdk-go-v2/credentials v1.17.65/go.mod h1:4zyjAuGOdikpNYiSGpsGz8hLGmUzlY8pc8r9QQ/RXYQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.14 h1:2scbY6//jy/s8+5vGrk7l1+UtHl0h9A4MjOO2k/TM2E= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.14/go.mod h1:bRpZPHZpSe5YRHmPfK3h1M7UBFCn2szHzyx0rw04zro= -github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.16 h1:Wg+SyAmJFupMcHW9CHn2QK0M5nksu8JeXWVJIRVL8Nk= -github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.16/go.mod h1:t2tzigPR3e5R46iVnpIQrfVbA9AIuy5VLYqyk3gffjg= -github.com/aws/aws-sdk-go-v2/service/route53 v1.48.8 h1:abeu0IVRqYXSts7Tl1Yoi/BxC59xdXYX0uVSN0fbPOk= -github.com/aws/aws-sdk-go-v2/service/route53 v1.48.8/go.mod h1:bOsuAIYHQbL+AqCldJ286MeljQL1sjUVGlpz9JMxCRM= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.16 h1:YV6xIKDJp6U7YB2bxfud9IENO1LRpGhe2Tv/OKtPrOQ= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.16/go.mod h1:DvbmMKgtpA6OihFJK13gHMZOZrCHttz8wPHGKXqU+3o= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.15 h1:kMyK3aKotq1aTBsj1eS8ERJLjqYRRRcsmP33ozlCvlk= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.15/go.mod h1:5uPZU7vSNzb8Y0dm75xTikinegPYK3uJmIHQZFq5Aqo= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.15 h1:ht1jVmeeo2anR7zDiYJLSnRYnO/9NILXXu42FP3rJg0= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.15/go.mod h1:xWZ5cOiFe3czngChE4LhCBqUxNwgfwndEF7XlYP/yD8= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY= +github.com/aws/aws-sdk-go-v2/service/lightsail v1.43.1 h1:0j58UseBtLuBcP6nY2z4SM1qZEvLF0ylyH6+ggnphLg= +github.com/aws/aws-sdk-go-v2/service/lightsail v1.43.1/go.mod h1:Qy22QnQSdHbZwMZrarsWZBIuK51isPlkD+Z4sztxX0o= +github.com/aws/aws-sdk-go-v2/service/route53 v1.50.0 h1:/nkJHXtJXJeelXHqG0898+fWKgvfaXBhGzbCsSmn9j8= +github.com/aws/aws-sdk-go-v2/service/route53 v1.50.0/go.mod h1:kGYOjvTa0Vw0qxrqrOLut1vMnui6qLxqv/SX3vYeM8Y= +github.com/aws/aws-sdk-go-v2/service/sso v1.25.2 h1:pdgODsAhGo4dvzC3JAG5Ce0PX8kWXrTZGx+jxADD+5E= +github.com/aws/aws-sdk-go-v2/service/sso v1.25.2/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.0 h1:90uX0veLKcdHVfvxhkWUQSCi5VabtwMLFutYiRke4oo= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.0/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 h1:PZV5W8yk4OtH1JAuhV2PXwwO9v5G5Aoj+eMCn4T+1Kc= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.17/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4= github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.22.3 h1:Z//5NuZCSW6R4PhQ93hShNbyBbn8BWCmCVCt+Q8Io5k= github.com/aws/smithy-go v1.22.3/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= @@ -765,13 +763,9 @@ github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/bsm/redislock v0.9.4 h1:X/Wse1DPpiQgHbVYRE9zv6m070UcKoOGekgvpNhiSvw= github.com/bsm/redislock v0.9.4/go.mod h1:Epf7AJLiSFwLCiZcfi6pWFO/8eAYrYpQXFxEDPoDeAk= -github.com/bytedance/sonic v1.12.9 h1:Od1BvK55NnewtGaJsTDeAOSnLVO2BTSLOe0+ooKokmQ= -github.com/bytedance/sonic v1.12.9/go.mod h1:uVvFidNmlt9+wa31S1urfwwthTWteBgG0hWuoKAXTx8= -github.com/bytedance/sonic v1.13.1 h1:Jyd5CIvdFnkOWuKXr+wm4Nyk2h0yAFsr8ucJgEasO3g= -github.com/bytedance/sonic v1.13.1/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= +github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= +github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/bytedance/sonic/loader v0.2.3 h1:yctD0Q3v2NOGfSWPLPvG2ggA2kV6TS6s4wioyEqssH0= -github.com/bytedance/sonic/loader v0.2.3/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY= github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw= @@ -779,8 +773,6 @@ github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdf github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA= github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U= github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= -github.com/casdoor/casdoor-go-sdk v1.4.0 h1:EhnIcMeCPiDE66tedy6EISkVjndR78slnwXqTfUnyhU= -github.com/casdoor/casdoor-go-sdk v1.4.0/go.mod h1:cMnkCQJgMYpgAlgEx8reSt1AVaDIQLcJ1zk5pzBaz+4= github.com/casdoor/casdoor-go-sdk v1.5.0 h1:mlKWG2NcQfpR1w+TyOtzPtupfgseuDMSqykP1gJq+g0= github.com/casdoor/casdoor-go-sdk v1.5.0/go.mod h1:cMnkCQJgMYpgAlgEx8reSt1AVaDIQLcJ1zk5pzBaz+4= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= @@ -801,8 +793,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= -github.com/civo/civogo v0.3.94 h1:VhdqaJ2m4z8Jz8arzyzVjokRnO8JQ3lGjLKLshJ1eJI= -github.com/civo/civogo v0.3.94/go.mod h1:LaEbkszc+9nXSh4YNG0sYXFGYqdQFmXXzQg0gESs2hc= +github.com/civo/civogo v0.3.96 h1:9R3yZS3B8B0oAqIlNDnMvsONk0mqZUkHREd0EH6HRIc= +github.com/civo/civogo v0.3.96/go.mod h1:LaEbkszc+9nXSh4YNG0sYXFGYqdQFmXXzQg0gESs2hc= github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.115.0 h1:84/dxeeXweCc0PN5Cto44iTA8AkG1fyT11yPO5ZB7sM= @@ -882,8 +874,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= -github.com/exoscale/egoscale/v3 v3.1.9 h1:kC876X4GKsojoqzJtq/MxNG91ebrDVEM9Ro+XOL7Yts= -github.com/exoscale/egoscale/v3 v3.1.9/go.mod h1:t9+MpSEam94na48O/xgvvPFpQPRiwZ3kBN4/UuQtKco= +github.com/exoscale/egoscale/v3 v3.1.13 h1:CAGC7QRjp2AiGj01agsSD0VKCp4OZmW5f51vV2IguNQ= +github.com/exoscale/egoscale/v3 v3.1.13/go.mod h1:t9+MpSEam94na48O/xgvvPFpQPRiwZ3kBN4/UuQtKco= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= @@ -926,10 +918,6 @@ github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T github.com/go-acme/lego/v4 v4.22.2 h1:ck+HllWrV/rZGeYohsKQ5iKNnU/WAZxwOdiu6cxky+0= github.com/go-acme/lego/v4 v4.22.2/go.mod h1:E2FndyI3Ekv0usNJt46mFb9LVpV/XBYT+4E3tz02Tzo= github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s= -github.com/go-co-op/gocron/v2 v2.15.0 h1:Kpvo71VSihE+RImmpA+3ta5CcMhoRzMGw4dJawrj4zo= -github.com/go-co-op/gocron/v2 v2.15.0/go.mod h1:ZF70ZwEqz0OO4RBXE1sNxnANy/zvwLcattWEFsqpKig= -github.com/go-co-op/gocron/v2 v2.16.0 h1:uqUF6WFZ4enRU45pWFNcn1xpDLc+jBOTKhPQI16Z1xs= -github.com/go-co-op/gocron/v2 v2.16.0/go.mod h1:opexeOFy5BplhsKdA7bzY9zeYih8I8/WNJ4arTIFPVc= github.com/go-co-op/gocron/v2 v2.16.1 h1:ux/5zxVRveCaCuTtNI3DiOk581KC1KpJbpJFYUEVYwo= github.com/go-co-op/gocron/v2 v2.16.1/go.mod h1:opexeOFy5BplhsKdA7bzY9zeYih8I8/WNJ4arTIFPVc= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= @@ -943,10 +931,10 @@ github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmn github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gormigrate/gormigrate/v2 v2.1.3 h1:ei3Vq/rpPI/jCJY9mRHJAKg5vU+EhZyWhBAkaAomQuw= -github.com/go-gormigrate/gormigrate/v2 v2.1.3/go.mod h1:VJ9FIOBAur+NmQ8c4tDVwOuiJcgupTG105FexPFrXzA= -github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= -github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= +github.com/go-gormigrate/gormigrate/v2 v2.1.4 h1:KOPEt27qy1cNzHfMZbp9YTmEuzkY4F4wrdsJW9WFk1U= +github.com/go-gormigrate/gormigrate/v2 v2.1.4/go.mod h1:y/6gPAH6QGAgP1UfHMiXcqGeJ88/GRQbfCReE1JJD5Y= +github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= +github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= @@ -976,13 +964,13 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8= -github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus= +github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= +github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM= github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -github.com/go-sql-driver/mysql v1.9.0 h1:Y0zIbQXhQKmQgTp44Y1dp3wTXcn804QoTptLZT1vtvo= -github.com/go-sql-driver/mysql v1.9.0/go.mod h1:pDetrLJeA3oMujJuvXc8RJoasr589B6A9fwzD3QMrqw= +github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtSb/iI= +github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= @@ -990,12 +978,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/go-webauthn/webauthn v0.12.1 h1:fQNKWc+gd7i1TW8FmlB0jQTHyc2GYYlV/QdLUxo+MSA= -github.com/go-webauthn/webauthn v0.12.1/go.mod h1:Q13xKHZi459wU8IoFjm8jQ6CMRyad+kegblwMFFhQGU= github.com/go-webauthn/webauthn v0.12.2 h1:yLaNPgBUEXDQtWnOjhsGhMMCEWbXwjg/aNkC8riJQI8= github.com/go-webauthn/webauthn v0.12.2/go.mod h1:Q8SZPPj4sZ469fNTcQXxRpzJOdb30jQrn/36FX8jilA= -github.com/go-webauthn/x v0.1.18 h1:9xxiKRKCHx/1R2RF+4xb1qY5QDIO0RlTmH5L02lmRH4= -github.com/go-webauthn/x v0.1.18/go.mod h1:Q/uHdGGFrZ7psEcoEStYunurZuG3Z9UDZJetM8qDTtA= github.com/go-webauthn/x v0.1.19 h1:IUfdHiBRoTdujpBA/14qbrMXQ3LGzYe/PRGWdZcmudg= github.com/go-webauthn/x v0.1.19/go.mod h1:C5arLuTQ3pVHKPw89v7CDGnqAZSZJj+4Jnr40dsn7tk= github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= @@ -1017,10 +1001,8 @@ github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptG github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= -github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= -github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= @@ -1087,8 +1069,8 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= @@ -1135,8 +1117,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= -github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= +github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= +github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= @@ -1221,7 +1203,6 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= @@ -1235,8 +1216,8 @@ github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKEN github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.136 h1:T785NUg5245nWpPVHLVR8lBd+zGQYR14Vi/TCX1iu3A= -github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.136/go.mod h1:Y/+YLCFCJtS29i2MbYPTUlNNfwXvkzEsZKR0imY/2aY= +github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.142 h1:9iOJ8tfNLw8uSiR5yx7VcHEYSOajJq5hb9SXF0BCUdA= +github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.142/go.mod h1:Y/+YLCFCJtS29i2MbYPTUlNNfwXvkzEsZKR0imY/2aY= github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -1359,8 +1340,6 @@ github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8 github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= -github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= @@ -1396,8 +1375,8 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/linode/linodego v1.47.0 h1:6MFNCyzWbr8Rhl4r7d5DwZLwxvFIsM4ARH6W0KS/R0U= -github.com/linode/linodego v1.47.0/go.mod h1:vyklQRzZUWhFVBZdYx4dcYJU/gG9yKB9VUcUs6ub0Lk= +github.com/linode/linodego v1.48.1 h1:Ojw1S+K5jJr1dggO8/H6r4FINxXnJbOU5GkbpaTfmhU= +github.com/linode/linodego v1.48.1/go.mod h1:fc3t60If8X+yZTFAebhCnNDFrhwQhq9HDU92WnBousQ= github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs= github.com/liquidweb/go-lwApi v0.0.5/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs= github.com/liquidweb/liquidweb-cli v0.6.9/go.mod h1:cE1uvQ+x24NGUL75D0QagOFCG8Wdvmwu8aL9TLmA/eQ= @@ -1405,16 +1384,14 @@ github.com/liquidweb/liquidweb-cli v0.7.0 h1:7j1r1U0MZa1TXiWo3IMU5V1YQwnBHMVxU+x github.com/liquidweb/liquidweb-cli v0.7.0/go.mod h1:+uU7L6BhaQtgo4cYKhhsP5UNCq/imNvjBjlf76Vqpb0= github.com/liquidweb/liquidweb-go v1.6.4 h1:6S0m3hHSpiLqGD7AFSb7lH/W/qr1wx+tKil9fgIbjMc= github.com/liquidweb/liquidweb-go v1.6.4/go.mod h1:B934JPIIcdA+uTq2Nz5PgOtG6CuCaEvQKe/Ge/5GgZ4= -github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 h1:7UMa6KCCMjZEMDtTVdcGu0B1GmmC7QJKiCCjyTAWQy0= -github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= +github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc= +github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= -github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -1454,8 +1431,8 @@ github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKju github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/miekg/dns v1.1.47/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= -github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= -github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= +github.com/miekg/dns v1.1.64 h1:wuZgD9wwCE6XMT05UU/mlSko71eRSXEAm2EbjQXLKnQ= +github.com/miekg/dns v1.1.64/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck= github.com/mimuret/golang-iij-dpf v0.9.1 h1:Gj6EhHJkOhr+q2RnvRPJsPMcjuVnWPSccEHyoEehU34= github.com/mimuret/golang-iij-dpf v0.9.1/go.mod h1:sl9KyOkESib9+KRD3HaGpgi1xk7eoN2+d96LCLsME2M= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= @@ -1505,10 +1482,10 @@ github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uY github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nrdcg/auroradns v1.1.0 h1:KekGh8kmf2MNwqZVVYo/fw/ZONt8QMEmbMFOeljteWo= github.com/nrdcg/auroradns v1.1.0/go.mod h1:O7tViUZbAcnykVnrGkXzIJTHoQCHcgalgAe6X1mzHfk= -github.com/nrdcg/bunny-go v0.0.0-20240207213615-dde5bf4577a3 h1:ouZ2JWDl8IW5k1qugYbmpbmW8hn85Ig6buSMBRlz3KI= -github.com/nrdcg/bunny-go v0.0.0-20240207213615-dde5bf4577a3/go.mod h1:ZwadWt7mVhMHMbAQ1w8IhDqtWO3eWqWq72W7trnaiE8= -github.com/nrdcg/desec v0.10.0 h1:qrEDiqnsvNU9QE7lXIXi/tIHAfyaFXKxF2/8/52O8uM= -github.com/nrdcg/desec v0.10.0/go.mod h1:5+4vyhMRTs49V9CNoODF/HwT8Mwxv9DJ6j+7NekUnBs= +github.com/nrdcg/bunny-go v0.0.0-20250327222614-988a091fc7ea h1:OSgRS4kqOs/WuxuFOObP2gwrenL4/qiKXQbQugr/Two= +github.com/nrdcg/bunny-go v0.0.0-20250327222614-988a091fc7ea/go.mod h1:IDRRngAngb2eTEaWgpO0hukQFI/vJId46fT1KErMytA= +github.com/nrdcg/desec v0.11.0 h1:XZVHy07sg12y8FozMp+l7XvzPsdzog0AYXuQMaHBsfs= +github.com/nrdcg/desec v0.11.0/go.mod h1:5+4vyhMRTs49V9CNoODF/HwT8Mwxv9DJ6j+7NekUnBs= github.com/nrdcg/dnspod-go v0.4.0 h1:c/jn1mLZNKF3/osJ6mz3QPxTudvPArXTjpkmYj0uK6U= github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ= github.com/nrdcg/freemyip v0.3.0 h1:0D2rXgvLwe2RRaVIjyUcQ4S26+cIS2iFwnhzDsEuuwc= @@ -1555,8 +1532,8 @@ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYr github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A= github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU= github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE= -github.com/oracle/oci-go-sdk/v65 v65.83.2 h1:4DtSCVe/AaHcqb08wXgjplOM8+tc4pqNwcUYZmplbv8= -github.com/oracle/oci-go-sdk/v65 v65.83.2/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0= +github.com/oracle/oci-go-sdk/v65 v65.88.0 h1:SbsGKsoRRxJxVTbwUyIPCPwPsHWb8aPgEEpo6qfRJnI= +github.com/oracle/oci-go-sdk/v65 v65.88.0/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0= github.com/ovh/go-ovh v1.7.0 h1:V14nF7FwDjQrZt9g7jzcvAAQ3HN6DNShRFRMC3jLoPw= github.com/ovh/go-ovh v1.7.0/go.mod h1:cTVDnl94z4tl8pP1uZ/8jlVxntjSIf09bNcQ5TJSC7c= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -1632,10 +1609,6 @@ github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= -github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= -github.com/redis/go-redis/v9 v9.7.1 h1:4LhKRCIduqXqtvCUlaq9c8bdHOkICjDMrr1+Zb3osAc= -github.com/redis/go-redis/v9 v9.7.1/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM= github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA= github.com/regfish/regfish-dnsapi-go v0.1.1 h1:TJFtbePHkd47q5GZwYl1h3DIYXmoxdLjW/SBsPtB5IE= @@ -1668,28 +1641,20 @@ github.com/sacloud/iaas-api-go v1.14.0/go.mod h1:C8os2Mnj0TOmMdSllwhaDWKMVG2ysFn github.com/sacloud/packages-go v0.0.11 h1:hrRWLmfPM9w7GBs6xb5/ue6pEMl8t1UuDKyR/KfteHo= github.com/sacloud/packages-go v0.0.11/go.mod h1:XNF5MCTWcHo9NiqWnYctVbASSSZR3ZOmmQORIzcurJ8= github.com/sagikazarmark/crypt v0.10.0/go.mod h1:gwTNHQVoOS3xp9Xvz5LLR+1AauC5M6880z5NWzdhOyQ= -github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= -github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= -github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= -github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k= +github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew= github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o= -github.com/sashabaranov/go-openai v1.37.0 h1:hQQowgYm4OXJ1Z/wTrE+XZaO20BYsL0R3uRPSpfNZkY= -github.com/sashabaranov/go-openai v1.37.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= -github.com/sashabaranov/go-openai v1.38.0 h1:hNN5uolKwdbpiqOn7l+Z2alch/0n0rSFyg4n+GZxR5k= -github.com/sashabaranov/go-openai v1.38.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= github.com/sashabaranov/go-openai v1.38.1 h1:TtZabbFQZa1nEni/IhVtDF/WQjVqDgd+cWR5OeddzF8= github.com/sashabaranov/go-openai v1.38.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.32 h1:4+LP7qmsLSGbmc66m1s5dKRMBwztRppfxFKlYqYte/c= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.32/go.mod h1:kzh+BSAvpoyHHdHBCDhmSWtBc1NbLMZ2lWHqnBoxFks= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33 h1:KhF0WejiUTDbL5X55nXowP7zNopwpowa6qaMAWyIE+0= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33/go.mod h1:792k1RTU+5JeMXm35/e2Wgp71qPH/DmDoZrRc+EFZDk= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/selectel/domains-go v1.1.0 h1:futG50J43ALLKQAnZk9H9yOtLGnSUh7c5hSvuC5gSHo= github.com/selectel/domains-go v1.1.0/go.mod h1:SugRKfq4sTpnOHquslCpzda72wV8u0cMBHx0C0l+bzA= github.com/selectel/go-selvpcclient/v3 v3.2.1 h1:ny6WIAMiHzKxOgOEnwcWE79wIQij1AHHylzPA41MXCw= github.com/selectel/go-selvpcclient/v3 v3.2.1/go.mod h1:3EfSf8aEWyhspOGbvZ6mvnFg7JN5uckxNyBFPGWsXNQ= -github.com/shirou/gopsutil/v4 v4.25.1 h1:QSWkTc+fu9LTAWfkZwZ6j8MSUk4A2LV7rbH0ZqmLjXs= -github.com/shirou/gopsutil/v4 v4.25.1/go.mod h1:RoUCUpndaJFtT+2zsZzzmhvbfGoDCJ7nFXKJf8GqJbI= github.com/shirou/gopsutil/v4 v4.25.2 h1:NMscG3l2CqtWFS86kj3vP7soOczqrQYIEhO/pMvvQkk= github.com/shirou/gopsutil/v4 v4.25.2/go.mod h1:34gBYJzyqCDT11b6bMHP0XCvWeU3J61XRT7a2EmCRTA= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -1732,8 +1697,8 @@ github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= -github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= -github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= +github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= +github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= @@ -1750,8 +1715,8 @@ github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= -github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= -github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= +github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= @@ -1781,21 +1746,22 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69 github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1101 h1:pz6QIjHR7TXQfEogg4pwvvTDgsB1L+RQGgnr2tBDzc4= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1101/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1101 h1:9c05Ky7Ppww06YFE579TjI89pfNnC2zdJufx7SXUTi8= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1101/go.mod h1:fBdcH58lmwIwePei24b9QFdE1w8+brIX9yTrf82n7yM= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1128/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1133 h1:S+ZHcAfI8+ii4MfsCr41R3CdhlTsc5OddGsCfeYJdl8= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1133/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1128 h1:mrJ5Fbkd7sZIJ5F6oRfh5zebPQaudPH9Y0+GUmFytYU= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1128/go.mod h1:zbsYIBT+VTX4z4ocjTAdLBIWyNYj3z0BRqd0iPdnjsk= github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= -github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= -github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY= -github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPDo= -github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI= +github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= +github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= +github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= +github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/transip/gotransip/v6 v6.26.0 h1:Aejfvh8rSp8Mj2GX/RpdBjMCv+Iy/DmgfNgczPDP550= github.com/transip/gotransip/v6 v6.26.0/go.mod h1:x0/RWGRK/zob817O3tfO2xhFoP1vu8YOHORx6Jpk80s= -github.com/tufanbarisyildirim/gonginx v0.0.0-20250120210832-12a9c7ae0c8a h1:bFMBmB409YhHd+B4yfM7JPYTCgxnQjqzIfFOiN4Tpsc= -github.com/tufanbarisyildirim/gonginx v0.0.0-20250120210832-12a9c7ae0c8a/go.mod h1:hdMWBc1+TyB6G5ZZBBgPWQ8cjRZ6zpYdhal0uu6E9QM= +github.com/tufanbarisyildirim/gonginx v0.0.0-20250225174229-c03497ddaef6 h1:HmtcQ7w07RI2SdTKkPf+NM8R33B1oR9MjIZYzlBizwA= +github.com/tufanbarisyildirim/gonginx v0.0.0-20250225174229-c03497ddaef6/go.mod h1:hdMWBc1+TyB6G5ZZBBgPWQ8cjRZ6zpYdhal0uu6E9QM= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= @@ -1807,16 +1773,8 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec h1:2s/ghQ8wKE+UzD/hf3P4Gd1j0JI9ncbxv+nsypPoUYI= github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec/go.mod h1:BZr7Qs3ku1ckpqed8tCRSqTlp8NAeZfAVpfx4OzXMss= -github.com/uozi-tech/cosy v1.14.4 h1:9X9CzxYjTg9DRQKgBjYvDNOAYYFclOXYYq518nO4vr0= -github.com/uozi-tech/cosy v1.14.4/go.mod h1:DSKLtoVaGLUlJ8KiQ1vWEsnv85epRrAAMXSijuq+asM= -github.com/uozi-tech/cosy v1.14.5 h1:hZ4wGf+558myDayc/KtCVv6MDCwd2pE6q6AUeF+EKI8= -github.com/uozi-tech/cosy v1.14.5/go.mod h1:KWo+XpzLiO3EUWJkXT7ca4nxX+vDVH0eB0B1BrOBkqg= -github.com/uozi-tech/cosy v1.15.5 h1:rSnFYUzJQreKeFSyOEPTjv7PknSFjO5m2mB/jV2Z32s= -github.com/uozi-tech/cosy v1.15.5/go.mod h1:b6VfiTeaIzMOKeUdjGz6cC2Nu3hnPLJfHsLe8zmfjvE= -github.com/uozi-tech/cosy v1.15.6 h1:IMU3Gf0mlmi7CF87Ujnyc8Iu7wdv0eEE+olDOuNPZz8= -github.com/uozi-tech/cosy v1.15.6/go.mod h1:b6VfiTeaIzMOKeUdjGz6cC2Nu3hnPLJfHsLe8zmfjvE= -github.com/uozi-tech/cosy v1.16.0 h1:hKFM8sOaedzaRCuHM1EnY8q0BAvsvFVDhTrJ3IHZEk0= -github.com/uozi-tech/cosy v1.16.0/go.mod h1:jEyznv+lmbb0YO0gU//yn4PnyqncTlyV2H5BpDa5aEw= +github.com/uozi-tech/cosy v1.17.0 h1:qrdBhbylsHGIOUcUsZKUdVzq8fLvePIclHVSGdszyxk= +github.com/uozi-tech/cosy v1.17.0/go.mod h1:jEyznv+lmbb0YO0gU//yn4PnyqncTlyV2H5BpDa5aEw= github.com/uozi-tech/cosy-driver-mysql v0.2.2 h1:22S/XNIvuaKGqxQPsYPXN8TZ8hHjCQdcJKVQ83Vzxoo= github.com/uozi-tech/cosy-driver-mysql v0.2.2/go.mod h1:EZnRIbSj1V5U0gEeTobrXai/d1SV11lkl4zP9NFEmyE= github.com/uozi-tech/cosy-driver-postgres v0.2.1 h1:OICakGuT+omva6QOJCxTJ5Lfr7CGXLmk/zD+aS51Z2o= @@ -1828,10 +1786,10 @@ github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjc github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y= github.com/vinyldns/go-vinyldns v0.9.16 h1:GZJStDkcCk1F1AcRc64LuuMh+ENL8pHA0CVd4ulRMcQ= github.com/vinyldns/go-vinyldns v0.9.16/go.mod h1:5qIJOdmzAnatKjurI+Tl4uTus7GJKJxb+zitufjHs3Q= -github.com/volcengine/volc-sdk-golang v1.0.195 h1:hKX4pBhmKcB3652BTdcAmtgizEPBnoQUpTM+j5blMA4= -github.com/volcengine/volc-sdk-golang v1.0.195/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ= -github.com/vultr/govultr/v3 v3.14.1 h1:9BpyZgsWasuNoR39YVMcq44MSaF576Z4D+U3ro58eJQ= -github.com/vultr/govultr/v3 v3.14.1/go.mod h1:q34Wd76upKmf+vxFMgaNMH3A8BbsPBmSYZUGC8oZa5w= +github.com/volcengine/volc-sdk-golang v1.0.201 h1:AnKtLpuEGCLuH9Yd2TvhG0SeTa+u4+MpLotIMZCdBgU= +github.com/volcengine/volc-sdk-golang v1.0.201/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ= +github.com/vultr/govultr/v3 v3.18.0 h1:nTfxZW7/BRUDdZyEDSWzqrtyQgNolFPXBlwwJuM7EF8= +github.com/vultr/govultr/v3 v3.18.0/go.mod h1:q34Wd76upKmf+vxFMgaNMH3A8BbsPBmSYZUGC8oZa5w= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= @@ -1843,10 +1801,10 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/yandex-cloud/go-genproto v0.0.0-20250217111757-ccaea642a16c h1:WTK2XiEf68Uv0rT6mjrB5hKkwZvMnWWHPF3OjK/fYL8= -github.com/yandex-cloud/go-genproto v0.0.0-20250217111757-ccaea642a16c/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo= -github.com/yandex-cloud/go-sdk v0.0.0-20250210144447-399a857b9c4e h1:RiNKkceZPeMWLSIl31RSgPeSmpT9K7eTXOcA9YxTBfg= -github.com/yandex-cloud/go-sdk v0.0.0-20250210144447-399a857b9c4e/go.mod h1:OCW2kKPZ900GNQ9aKDaX7/FUQmxGdm+CKeXVocbM4d0= +github.com/yandex-cloud/go-genproto v0.0.0-20250325081613-cd85d9003939 h1:o1L5uP1z/IKGQpfzEqSmqGtFDIKDoFAvZuqpzySIVFc= +github.com/yandex-cloud/go-genproto v0.0.0-20250325081613-cd85d9003939/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo= +github.com/yandex-cloud/go-sdk v0.0.0-20250325134853-dcb34ef70818 h1:EgfskqIEIv/f5vx/guwfkakNwy5H9Mm+OC17zS1ofus= +github.com/yandex-cloud/go-sdk v0.0.0-20250325134853-dcb34ef70818/go.mod h1:U2Cc0SZ8kQHcL4ffnfNN78bdSybVP2pQNq0oJfFwvM8= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1872,8 +1830,8 @@ go.etcd.io/etcd/client/v2 v2.305.7/go.mod h1:GQGT5Z3TBuAQGvgPfhR7VPySu/SudxmEkRq go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA= go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo= -go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793SqyhzM= -go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ= +go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -1884,18 +1842,18 @@ go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I= -go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= -go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= -go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= -go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= -go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= -go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= -go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= -go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= -go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= -go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= +go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= +go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= +go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= @@ -1930,8 +1888,6 @@ go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/arch v0.14.0 h1:z9JUEZWr8x4rR0OU6c4/4t6E6jOZ8/QBS2bBYBm4tx4= -golang.org/x/arch v0.14.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw= golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1970,10 +1926,6 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= -golang.org/x/crypto v0.34.0 h1:+/C6tk6rf/+t5DhUketUbD1aNGqiSX3j15Z6xuIDlBA= -golang.org/x/crypto v0.34.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= -golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= -golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1991,8 +1943,6 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= -golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4= -golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -2035,8 +1985,6 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -2118,10 +2066,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= -golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2151,8 +2097,8 @@ golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= -golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE= -golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= +golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -2169,8 +2115,6 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -2294,8 +2238,6 @@ golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -2313,8 +2255,8 @@ golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= -golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2334,8 +2276,6 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2346,8 +2286,8 @@ golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= -golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= +golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2422,8 +2362,6 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2502,8 +2440,8 @@ google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60c google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= -google.golang.org/api v0.221.0 h1:qzaJfLhDsbMeFee8zBRdt/Nc+xmOuafD/dbdgGfutOU= -google.golang.org/api v0.221.0/go.mod h1:7sOU2+TL4TxUTdbi0gWgAIg7tH5qBXxoyhtL+9x3biQ= +google.golang.org/api v0.228.0 h1:X2DJ/uoWGnY5obVjewbp8icSL5U4FzuCfy9OjbLSnLs= +google.golang.org/api v0.228.0/go.mod h1:wNvRS1Pbe8r4+IfBIniV8fwCpGwTrYa+kMUDiC5z5a4= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2644,12 +2582,12 @@ google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOl google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= -google.golang.org/genproto v0.0.0-20250218202821-56aae31c358a h1:Xx6e5r1AOINOgm2ZuzvwDueGlOOml4PKBUry8jqyS6U= -google.golang.org/genproto v0.0.0-20250218202821-56aae31c358a/go.mod h1:Cmg1ztsSOnOsWxOiPTOUX8gegyHg5xADRncIHdtec8U= -google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0= -google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ= +google.golang.org/genproto v0.0.0-20250324211829-b45e905df463 h1:qEFnJI6AnfZk0NNe8YTyXQh5i//Zxi4gBHwRgp76qpw= +google.golang.org/genproto v0.0.0-20250324211829-b45e905df463/go.mod h1:SqIx1NV9hcvqdLHo7uNZDS5lrUJybQ3evo3+z/WBfA0= +google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463 h1:hE3bRWtU6uceqlh4fhrSnUyjKHMKB9KrTLLG+bc0ddM= +google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463/go.mod h1:U90ffi8eUL9MwPcrJylN5+Mk2v3vuPDptd5yyNUiRR8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -2692,8 +2630,8 @@ google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5v google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= -google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= -google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= +google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= +google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -2712,8 +2650,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -2725,8 +2663,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg= -gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI= gopkg.in/h2non/gock.v1 v1.0.15 h1:SzLqcIlb/fDfg7UvukMpNcWsu7sI5tWwL+KCATZqks0= gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= @@ -2793,14 +2729,14 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -k8s.io/api v0.32.2 h1:bZrMLEkgizC24G9eViHGOPbW+aRo9duEISRIJKfdJuw= -k8s.io/api v0.32.2/go.mod h1:hKlhk4x1sJyYnHENsrdCWw31FEmCijNGPJO5WzHiJ6Y= -k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ= -k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls= +k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k= +k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= +k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0= -k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro= +k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= @@ -2842,8 +2778,9 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= -sigs.k8s.io/structured-merge-diff/v4 v4.5.0 h1:nbCitCK2hfnhyiKo6uf2HxUPTCodY6Qaf85SbDIaMBk= -sigs.k8s.io/structured-merge-diff/v4 v4.5.0/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= +sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/internal/backup/backup.go b/internal/backup/backup.go new file mode 100644 index 00000000..39d44354 --- /dev/null +++ b/internal/backup/backup.go @@ -0,0 +1,169 @@ +package backup + +import ( + "bytes" + "encoding/base64" + "fmt" + "os" + "path/filepath" + "time" + + "github.com/0xJacky/Nginx-UI/internal/version" + "github.com/uozi-tech/cosy" + "github.com/uozi-tech/cosy/logger" +) + +// Directory and file names +const ( + BackupDirPrefix = "nginx-ui-backup-" + NginxUIDir = "nginx-ui" + NginxDir = "nginx" + HashInfoFile = "hash_info.txt" + NginxUIZipName = "nginx-ui.zip" + NginxZipName = "nginx.zip" +) + +// BackupResult contains the results of a backup operation +type BackupResult struct { + BackupContent []byte `json:"-"` // Backup content as byte array + BackupName string `json:"name"` // Backup file name + AESKey string `json:"aes_key"` // Base64 encoded AES key + AESIv string `json:"aes_iv"` // Base64 encoded AES IV +} + +// HashInfo contains hash information for verification +type HashInfo struct { + NginxUIHash string `json:"nginx_ui_hash"` + NginxHash string `json:"nginx_hash"` + Timestamp string `json:"timestamp"` + Version string `json:"version"` +} + +// Backup creates a backup of nginx-ui configuration and database files, +// and nginx configuration directory, compressed into an encrypted archive +func Backup() (BackupResult, error) { + // Generate timestamps for filenames + timestamp := time.Now().Format("20060102-150405") + backupName := fmt.Sprintf("backup-%s.zip", timestamp) + + // Generate AES key and IV + key, err := GenerateAESKey() + if err != nil { + return BackupResult{}, cosy.WrapErrorWithParams(ErrGenerateAESKey, err.Error()) + } + + iv, err := GenerateIV() + if err != nil { + return BackupResult{}, cosy.WrapErrorWithParams(ErrGenerateIV, err.Error()) + } + + // Create temporary directory for files to be archived + tempDir, err := os.MkdirTemp("", "nginx-ui-backup-*") + if err != nil { + return BackupResult{}, cosy.WrapErrorWithParams(ErrCreateTempDir, err.Error()) + } + defer os.RemoveAll(tempDir) + + // Create directories in temp + nginxUITempDir := filepath.Join(tempDir, NginxUIDir) + nginxTempDir := filepath.Join(tempDir, NginxDir) + if err := os.MkdirAll(nginxUITempDir, 0755); err != nil { + return BackupResult{}, cosy.WrapErrorWithParams(ErrCreateTempSubDir, err.Error()) + } + if err := os.MkdirAll(nginxTempDir, 0755); err != nil { + return BackupResult{}, cosy.WrapErrorWithParams(ErrCreateTempSubDir, err.Error()) + } + + // Backup nginx-ui config and database to a directory + if err := backupNginxUIFiles(nginxUITempDir); err != nil { + return BackupResult{}, cosy.WrapErrorWithParams(ErrBackupNginxUI, err.Error()) + } + + // Backup nginx configs to a directory + if err := backupNginxFiles(nginxTempDir); err != nil { + return BackupResult{}, cosy.WrapErrorWithParams(ErrBackupNginx, err.Error()) + } + + // Create individual zip files for nginx-ui and nginx directories + nginxUIZipPath := filepath.Join(tempDir, NginxUIZipName) + nginxZipPath := filepath.Join(tempDir, NginxZipName) + + // Create zip archives for each directory + if err := createZipArchive(nginxUIZipPath, nginxUITempDir); err != nil { + return BackupResult{}, cosy.WrapErrorWithParams(ErrCreateZipArchive, err.Error()) + } + + if err := createZipArchive(nginxZipPath, nginxTempDir); err != nil { + return BackupResult{}, cosy.WrapErrorWithParams(ErrCreateZipArchive, err.Error()) + } + + // Calculate hashes for the zip files + nginxUIHash, err := calculateFileHash(nginxUIZipPath) + if err != nil { + return BackupResult{}, cosy.WrapErrorWithParams(ErrCalculateHash, err.Error()) + } + + nginxHash, err := calculateFileHash(nginxZipPath) + if err != nil { + return BackupResult{}, cosy.WrapErrorWithParams(ErrCalculateHash, err.Error()) + } + + // Get current version information + versionInfo := version.GetVersionInfo() + + // Create hash info file + hashInfo := HashInfo{ + NginxUIHash: nginxUIHash, + NginxHash: nginxHash, + Timestamp: timestamp, + Version: versionInfo.Version, + } + + // Write hash info to file + hashInfoPath := filepath.Join(tempDir, HashInfoFile) + if err := writeHashInfoFile(hashInfoPath, hashInfo); err != nil { + return BackupResult{}, cosy.WrapErrorWithParams(ErrCreateHashFile, err.Error()) + } + + // Encrypt the individual files + if err := encryptFile(hashInfoPath, key, iv); err != nil { + return BackupResult{}, cosy.WrapErrorWithParams(ErrEncryptFile, HashInfoFile) + } + + if err := encryptFile(nginxUIZipPath, key, iv); err != nil { + return BackupResult{}, cosy.WrapErrorWithParams(ErrEncryptNginxUIDir, err.Error()) + } + + if err := encryptFile(nginxZipPath, key, iv); err != nil { + return BackupResult{}, cosy.WrapErrorWithParams(ErrEncryptNginxDir, err.Error()) + } + + // Remove the original directories to avoid duplicating them in the final archive + if err := os.RemoveAll(nginxUITempDir); err != nil { + return BackupResult{}, cosy.WrapErrorWithParams(ErrCleanupTempDir, err.Error()) + } + if err := os.RemoveAll(nginxTempDir); err != nil { + return BackupResult{}, cosy.WrapErrorWithParams(ErrCleanupTempDir, err.Error()) + } + + // Create final zip file to memory buffer + var buffer bytes.Buffer + if err := createZipArchiveToBuffer(&buffer, tempDir); err != nil { + return BackupResult{}, cosy.WrapErrorWithParams(ErrCreateZipArchive, err.Error()) + } + + // Convert AES key and IV to base64 encoded strings + keyBase64 := base64.StdEncoding.EncodeToString(key) + ivBase64 := base64.StdEncoding.EncodeToString(iv) + + // Return result + result := BackupResult{ + BackupContent: buffer.Bytes(), + BackupName: backupName, + AESKey: keyBase64, + AESIv: ivBase64, + } + + logger.Infof("Backup created successfully: %s", backupName) + return result, nil +} diff --git a/internal/backup/backup_crypto.go b/internal/backup/backup_crypto.go new file mode 100644 index 00000000..fb8e0319 --- /dev/null +++ b/internal/backup/backup_crypto.go @@ -0,0 +1,128 @@ +package backup + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/base64" + "io" + "os" + + "github.com/uozi-tech/cosy" +) + +// AESEncrypt encrypts data using AES-256-CBC +func AESEncrypt(data []byte, key []byte, iv []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, cosy.WrapErrorWithParams(ErrEncryptData, err.Error()) + } + + // Pad data to be a multiple of block size + padding := aes.BlockSize - (len(data) % aes.BlockSize) + padtext := make([]byte, len(data)+padding) + copy(padtext, data) + // PKCS#7 padding + for i := len(data); i < len(padtext); i++ { + padtext[i] = byte(padding) + } + + // Create CBC encrypter + mode := cipher.NewCBCEncrypter(block, iv) + encrypted := make([]byte, len(padtext)) + mode.CryptBlocks(encrypted, padtext) + + return encrypted, nil +} + +// AESDecrypt decrypts data using AES-256-CBC +func AESDecrypt(encrypted []byte, key []byte, iv []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, cosy.WrapErrorWithParams(ErrDecryptData, err.Error()) + } + + // Create CBC decrypter + mode := cipher.NewCBCDecrypter(block, iv) + decrypted := make([]byte, len(encrypted)) + mode.CryptBlocks(decrypted, encrypted) + + // Remove padding + padding := int(decrypted[len(decrypted)-1]) + if padding < 1 || padding > aes.BlockSize { + return nil, ErrInvalidPadding + } + return decrypted[:len(decrypted)-padding], nil +} + +// GenerateAESKey generates a random 32-byte AES key +func GenerateAESKey() ([]byte, error) { + key := make([]byte, 32) // 256-bit key + if _, err := io.ReadFull(rand.Reader, key); err != nil { + return nil, cosy.WrapErrorWithParams(ErrGenerateAESKey, err.Error()) + } + return key, nil +} + +// GenerateIV generates a random 16-byte initialization vector +func GenerateIV() ([]byte, error) { + iv := make([]byte, aes.BlockSize) + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return nil, cosy.WrapErrorWithParams(ErrGenerateIV, err.Error()) + } + return iv, nil +} + +// encryptFile encrypts a single file using AES encryption +func encryptFile(filePath string, key []byte, iv []byte) error { + // Read file content + data, err := os.ReadFile(filePath) + if err != nil { + return cosy.WrapErrorWithParams(ErrReadFile, filePath) + } + + // Encrypt file content + encrypted, err := AESEncrypt(data, key, iv) + if err != nil { + return cosy.WrapErrorWithParams(ErrEncryptFile, filePath) + } + + // Write encrypted content back + if err := os.WriteFile(filePath, encrypted, 0644); err != nil { + return cosy.WrapErrorWithParams(ErrWriteEncryptedFile, filePath) + } + + return nil +} + +// decryptFile decrypts a single file using AES decryption +func decryptFile(filePath string, key []byte, iv []byte) error { + // Read encrypted file content + encryptedData, err := os.ReadFile(filePath) + if err != nil { + return cosy.WrapErrorWithParams(ErrReadEncryptedFile, filePath) + } + + // Decrypt file content + decryptedData, err := AESDecrypt(encryptedData, key, iv) + if err != nil { + return cosy.WrapErrorWithParams(ErrDecryptFile, filePath) + } + + // Write decrypted content back + if err := os.WriteFile(filePath, decryptedData, 0644); err != nil { + return cosy.WrapErrorWithParams(ErrWriteDecryptedFile, filePath) + } + + return nil +} + +// EncodeToBase64 encodes byte slice to base64 string +func EncodeToBase64(data []byte) string { + return base64.StdEncoding.EncodeToString(data) +} + +// DecodeFromBase64 decodes base64 string to byte slice +func DecodeFromBase64(encoded string) ([]byte, error) { + return base64.StdEncoding.DecodeString(encoded) +} diff --git a/internal/backup/backup_nginx_ui.go b/internal/backup/backup_nginx_ui.go new file mode 100644 index 00000000..cfad3163 --- /dev/null +++ b/internal/backup/backup_nginx_ui.go @@ -0,0 +1,76 @@ +package backup + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/0xJacky/Nginx-UI/settings" + "github.com/uozi-tech/cosy" + "github.com/uozi-tech/cosy/logger" + cosysettings "github.com/uozi-tech/cosy/settings" +) + +// backupNginxUIFiles backs up the nginx-ui configuration and database files +func backupNginxUIFiles(destDir string) error { + // Get config file path + configPath := cosysettings.ConfPath + if configPath == "" { + return ErrConfigPathEmpty + } + + // Always save the config file as app.ini, regardless of its original name + destConfigPath := filepath.Join(destDir, "app.ini") + if err := copyFile(configPath, destConfigPath); err != nil { + return cosy.WrapErrorWithParams(ErrCopyConfigFile, err.Error()) + } + + // Get database file name and path + dbName := settings.DatabaseSettings.GetName() + dbFile := dbName + ".db" + + // Database directory is the same as config file directory + dbDir := filepath.Dir(configPath) + dbPath := filepath.Join(dbDir, dbFile) + + // Copy database file + if _, err := os.Stat(dbPath); err == nil { + // Database exists as file + destDBPath := filepath.Join(destDir, dbFile) + if err := copyFile(dbPath, destDBPath); err != nil { + return cosy.WrapErrorWithParams(ErrCopyDBFile, err.Error()) + } + } else { + logger.Warn("Database file not found: %s", dbPath) + } + + return nil +} + +// backupNginxFiles backs up the nginx configuration directory +func backupNginxFiles(destDir string) error { + // Get nginx config directory + nginxConfigDir := settings.NginxSettings.ConfigDir + if nginxConfigDir == "" { + return ErrNginxConfigDirEmpty + } + + // Copy nginx config directory + if err := copyDirectory(nginxConfigDir, destDir); err != nil { + return cosy.WrapErrorWithParams(ErrCopyNginxConfigDir, err.Error()) + } + + return nil +} + +// writeHashInfoFile creates a hash information file for verification +func writeHashInfoFile(hashFilePath string, info HashInfo) error { + content := fmt.Sprintf("nginx-ui_hash: %s\nnginx_hash: %s\ntimestamp: %s\nversion: %s\n", + info.NginxUIHash, info.NginxHash, info.Timestamp, info.Version) + + if err := os.WriteFile(hashFilePath, []byte(content), 0644); err != nil { + return cosy.WrapErrorWithParams(ErrCreateHashFile, err.Error()) + } + + return nil +} diff --git a/internal/backup/backup_test.go b/internal/backup/backup_test.go new file mode 100644 index 00000000..290a38fd --- /dev/null +++ b/internal/backup/backup_test.go @@ -0,0 +1,466 @@ +package backup + +import ( + "os" + "path/filepath" + "testing" + + "github.com/0xJacky/Nginx-UI/settings" + "github.com/stretchr/testify/assert" + cosylogger "github.com/uozi-tech/cosy/logger" + cosysettings "github.com/uozi-tech/cosy/settings" +) + +func init() { + // Initialize logging system to avoid nil pointer exceptions during tests + cosylogger.Init("debug") + + // Clean up backup files at the start of tests + cleanupBackupFiles() +} + +// cleanupBackupFiles removes all backup files in the current directory +func cleanupBackupFiles() { + // Get current directory + dir, err := os.Getwd() + if err != nil { + return + } + + // Delete all backup files + matches, err := filepath.Glob(filepath.Join(dir, "backup-*.zip")) + if err == nil { + for _, file := range matches { + os.Remove(file) + } + } +} + +// setupTestEnvironment creates a temporary environment for testing +func setupTestEnvironment(t *testing.T) (string, func()) { + // Create temporary test directory + tempDir, err := os.MkdirTemp("", "backup-test-*") + assert.NoError(t, err) + + // Set up necessary directories + nginxDir := filepath.Join(tempDir, "nginx") + nginxUIDir := filepath.Join(tempDir, "nginx-ui") + configDir := filepath.Join(tempDir, "config") + backupDir := filepath.Join(tempDir, "backup") + + // Create directories + for _, dir := range []string{nginxDir, nginxUIDir, configDir, backupDir} { + err = os.MkdirAll(dir, 0755) + assert.NoError(t, err) + } + + // Create some test files + testFiles := map[string]string{ + filepath.Join(nginxDir, "nginx.conf"): "user nginx;\nworker_processes auto;\n", + filepath.Join(nginxUIDir, "config.json"): `{"version": "1.0", "settings": {"theme": "dark"}}`, + } + + for file, content := range testFiles { + err = os.WriteFile(file, []byte(content), 0644) + assert.NoError(t, err) + } + + // Save original configuration + origNginxConfigDir := settings.NginxSettings.ConfigDir + origNginxUIConfigPath := cosysettings.ConfPath + + // Set test configuration + settings.NginxSettings.ConfigDir = nginxDir + cosysettings.ConfPath = filepath.Join(configDir, "config.ini") + + // Return cleanup function + cleanup := func() { + // Restore original configuration + settings.NginxSettings.ConfigDir = origNginxConfigDir + cosysettings.ConfPath = origNginxUIConfigPath + + // Delete temporary directory + os.RemoveAll(tempDir) + } + + return tempDir, cleanup +} + +// Test backup and restore functionality +func TestBackupAndRestore(t *testing.T) { + // Make sure backup files are cleaned up at the start and end of the test + cleanupBackupFiles() + defer cleanupBackupFiles() + + // Create test configuration + tempDir, err := os.MkdirTemp("", "nginx-ui-backup-test-*") + assert.NoError(t, err) + defer os.RemoveAll(tempDir) + + // Create config file + configPath := filepath.Join(tempDir, "config.ini") + testConfig := []byte("[app]\nName = Nginx UI Test\n") + err = os.WriteFile(configPath, testConfig, 0644) + assert.NoError(t, err) + + // Create database file + dbName := settings.DatabaseSettings.GetName() + dbFile := dbName + ".db" + dbPath := filepath.Join(tempDir, dbFile) + testDB := []byte("CREATE TABLE users (id INT, name TEXT);") + err = os.WriteFile(dbPath, testDB, 0644) + assert.NoError(t, err) + + // Create nginx directory + nginxConfigDir := filepath.Join(tempDir, "nginx") + err = os.MkdirAll(nginxConfigDir, 0755) + assert.NoError(t, err) + + // Create test nginx config + testNginxContent := []byte("server {\n listen 80;\n server_name example.com;\n}\n") + err = os.WriteFile(filepath.Join(nginxConfigDir, "nginx.conf"), testNginxContent, 0644) + assert.NoError(t, err) + + // Setup settings for testing + originalConfPath := cosysettings.ConfPath + originalNginxConfigDir := settings.NginxSettings.ConfigDir + + cosysettings.ConfPath = configPath + settings.NginxSettings.ConfigDir = nginxConfigDir + + // Restore original settings after test + defer func() { + cosysettings.ConfPath = originalConfPath + settings.NginxSettings.ConfigDir = originalNginxConfigDir + }() + + // Run backup + result, err := Backup() + assert.NoError(t, err) + assert.NotEmpty(t, result.BackupContent) + assert.NotEmpty(t, result.BackupName) + assert.NotEmpty(t, result.AESKey) + assert.NotEmpty(t, result.AESIv) + + // Save backup content to a temporary file for restore testing + backupPath := filepath.Join(tempDir, result.BackupName) + err = os.WriteFile(backupPath, result.BackupContent, 0644) + assert.NoError(t, err) + + // Test restore functionality + restoreDir, err := os.MkdirTemp("", "nginx-ui-restore-test-*") + assert.NoError(t, err) + defer os.RemoveAll(restoreDir) + + // Decode AES key and IV + aesKey, err := DecodeFromBase64(result.AESKey) + assert.NoError(t, err) + aesIv, err := DecodeFromBase64(result.AESIv) + assert.NoError(t, err) + + // Perform restore + restoreResult, err := Restore(RestoreOptions{ + BackupPath: backupPath, + AESKey: aesKey, + AESIv: aesIv, + RestoreDir: restoreDir, + RestoreNginx: true, + RestoreNginxUI: true, + VerifyHash: true, + }) + assert.NoError(t, err) + assert.NotEmpty(t, restoreResult.RestoreDir) + + // Verify restored directories + nginxUIDir := filepath.Join(restoreDir, NginxUIDir) + nginxDir := filepath.Join(restoreDir, NginxDir) + + _, err = os.Stat(nginxUIDir) + assert.NoError(t, err) + _, err = os.Stat(nginxDir) + assert.NoError(t, err) + + // Verify hash info exists + _, err = os.Stat(filepath.Join(restoreDir, HashInfoFile)) + assert.NoError(t, err) +} + +// Test AES encryption/decryption +func TestEncryptionDecryption(t *testing.T) { + // Test data + testData := []byte("This is a test message to encrypt and decrypt") + + // Create temp dir for testing + testDir, err := os.MkdirTemp("", "nginx-ui-crypto-test-*") + assert.NoError(t, err) + defer os.RemoveAll(testDir) + + // Create test file + testFile := filepath.Join(testDir, "test.txt") + err = os.WriteFile(testFile, testData, 0644) + assert.NoError(t, err) + + // Generate AES key and IV + key, err := GenerateAESKey() + assert.NoError(t, err) + iv, err := GenerateIV() + assert.NoError(t, err) + + // Test encrypt file + err = encryptFile(testFile, key, iv) + assert.NoError(t, err) + + // Read encrypted data + encryptedData, err := os.ReadFile(testFile) + assert.NoError(t, err) + assert.NotEqual(t, string(testData), string(encryptedData)) + + // Test decrypt file + err = decryptFile(testFile, key, iv) + assert.NoError(t, err) + + // Read decrypted data + decryptedData, err := os.ReadFile(testFile) + assert.NoError(t, err) + assert.Equal(t, string(testData), string(decryptedData)) +} + +// Test AES direct encryption/decryption +func TestAESEncryptDecrypt(t *testing.T) { + // Generate key and IV + key, err := GenerateAESKey() + assert.NoError(t, err) + + iv, err := GenerateIV() + assert.NoError(t, err) + + // Test data + original := []byte("This is a test message for encryption and decryption") + + // Encrypt + encrypted, err := AESEncrypt(original, key, iv) + assert.NoError(t, err) + assert.NotEqual(t, original, encrypted) + + // Decrypt + decrypted, err := AESDecrypt(encrypted, key, iv) + assert.NoError(t, err) + assert.Equal(t, original, decrypted) +} + +// Test Base64 encoding/decoding +func TestEncodeDecodeBase64(t *testing.T) { + original := []byte("Test data for base64 encoding") + + // Encode + encoded := EncodeToBase64(original) + + // Decode + decoded, err := DecodeFromBase64(encoded) + assert.NoError(t, err) + assert.Equal(t, original, decoded) +} + +func TestGenerateAESKey(t *testing.T) { + key, err := GenerateAESKey() + assert.NoError(t, err) + assert.Equal(t, 32, len(key)) +} + +func TestGenerateIV(t *testing.T) { + iv, err := GenerateIV() + assert.NoError(t, err) + assert.Equal(t, 16, len(iv)) +} + +func TestEncryptDecryptFile(t *testing.T) { + // Create temp directory + tempDir, err := os.MkdirTemp("", "encrypt-file-test-*") + assert.NoError(t, err) + defer os.RemoveAll(tempDir) + + // Create test file + testFile := filepath.Join(tempDir, "test.txt") + testContent := []byte("This is test content for file encryption") + err = os.WriteFile(testFile, testContent, 0644) + assert.NoError(t, err) + + // Generate key and IV + key, err := GenerateAESKey() + assert.NoError(t, err) + + iv, err := GenerateIV() + assert.NoError(t, err) + + // Encrypt file + err = encryptFile(testFile, key, iv) + assert.NoError(t, err) + + // Read encrypted content + encryptedContent, err := os.ReadFile(testFile) + assert.NoError(t, err) + assert.NotEqual(t, testContent, encryptedContent) + + // Decrypt file + err = decryptFile(testFile, key, iv) + assert.NoError(t, err) + + // Read decrypted content + decryptedContent, err := os.ReadFile(testFile) + assert.NoError(t, err) + assert.Equal(t, testContent, decryptedContent) +} + +func TestBackupRestore(t *testing.T) { + // Set up test environment + tempDir, cleanup := setupTestEnvironment(t) + defer cleanup() + + // Create a config.ini file since it's required for the test + configDir := filepath.Join(tempDir, "config") + configPath := filepath.Join(configDir, "config.ini") + err := os.WriteFile(configPath, []byte("[app]\nName = Nginx UI Test\n"), 0644) + assert.NoError(t, err) + + // Update Cosy settings path + originalConfPath := cosysettings.ConfPath + cosysettings.ConfPath = configPath + defer func() { + cosysettings.ConfPath = originalConfPath + }() + + // Create backup + backupResult, err := Backup() + // If there's an error, log it but continue testing + if err != nil { + t.Logf("Backup failed with error: %v", err) + t.Fail() + return + } + + assert.NotNil(t, backupResult.BackupContent) + assert.NotEmpty(t, backupResult.BackupName) + assert.NotEmpty(t, backupResult.AESKey) + assert.NotEmpty(t, backupResult.AESIv) + + // Create temporary file for restore testing + backupPath := filepath.Join(tempDir, backupResult.BackupName) + err = os.WriteFile(backupPath, backupResult.BackupContent, 0644) + assert.NoError(t, err) + + // Decode key and IV + key, err := DecodeFromBase64(backupResult.AESKey) + assert.NoError(t, err) + + iv, err := DecodeFromBase64(backupResult.AESIv) + assert.NoError(t, err) + + // Create restore directory + restoreDir := filepath.Join(tempDir, "restore") + err = os.MkdirAll(restoreDir, 0755) + assert.NoError(t, err) + + // Create restore options + options := RestoreOptions{ + BackupPath: backupPath, + AESKey: key, + AESIv: iv, + RestoreDir: restoreDir, + VerifyHash: true, + // Avoid modifying the system + RestoreNginx: false, + RestoreNginxUI: false, + } + + // Test restore + result, err := Restore(options) + if err != nil { + t.Logf("Restore failed with error: %v", err) + t.Fail() + return + } + + assert.Equal(t, restoreDir, result.RestoreDir) + // If hash verification is enabled, check the result + if options.VerifyHash { + assert.True(t, result.HashMatch, "Hash verification should pass") + } +} + +func TestCreateZipArchive(t *testing.T) { + // Create temp directories + tempSourceDir, err := os.MkdirTemp("", "zip-source-test-*") + assert.NoError(t, err) + defer os.RemoveAll(tempSourceDir) + + // Create some test files + testFiles := []string{"file1.txt", "file2.txt", "subdir/file3.txt"} + testContent := []byte("Test content") + + for _, file := range testFiles { + filePath := filepath.Join(tempSourceDir, file) + dirPath := filepath.Dir(filePath) + + err = os.MkdirAll(dirPath, 0755) + assert.NoError(t, err) + + err = os.WriteFile(filePath, testContent, 0644) + assert.NoError(t, err) + } + + // Create zip file + zipPath := filepath.Join(tempSourceDir, "test.zip") + err = createZipArchive(zipPath, tempSourceDir) + assert.NoError(t, err) + + // Verify zip file was created + _, err = os.Stat(zipPath) + assert.NoError(t, err) + + // Extract to new directory to verify contents + extractDir := filepath.Join(tempSourceDir, "extract") + err = os.MkdirAll(extractDir, 0755) + assert.NoError(t, err) + + err = extractZipArchive(zipPath, extractDir) + assert.NoError(t, err) + + // Verify extracted files + for _, file := range testFiles { + extractedPath := filepath.Join(extractDir, file) + content, err := os.ReadFile(extractedPath) + assert.NoError(t, err) + assert.Equal(t, testContent, content) + } +} + +func TestHashCalculation(t *testing.T) { + // Create temp file + tempFile, err := os.CreateTemp("", "hash-test-*.txt") + assert.NoError(t, err) + defer os.Remove(tempFile.Name()) + + // Write content + testContent := []byte("Test content for hash calculation") + _, err = tempFile.Write(testContent) + assert.NoError(t, err) + tempFile.Close() + + // Calculate hash + hash, err := calculateFileHash(tempFile.Name()) + assert.NoError(t, err) + assert.NotEmpty(t, hash) + + // Calculate again to verify consistency + hash2, err := calculateFileHash(tempFile.Name()) + assert.NoError(t, err) + assert.Equal(t, hash, hash2) + + // Modify file and check hash changes + err = os.WriteFile(tempFile.Name(), []byte("Modified content"), 0644) + assert.NoError(t, err) + + hash3, err := calculateFileHash(tempFile.Name()) + assert.NoError(t, err) + assert.NotEqual(t, hash, hash3) +} diff --git a/internal/backup/backup_zip.go b/internal/backup/backup_zip.go new file mode 100644 index 00000000..385479bc --- /dev/null +++ b/internal/backup/backup_zip.go @@ -0,0 +1,290 @@ +package backup + +import ( + "archive/zip" + "bytes" + "crypto/sha256" + "encoding/hex" + "io" + "os" + "path/filepath" + + "github.com/uozi-tech/cosy" +) + +// createZipArchive creates a zip archive from a directory +func createZipArchive(zipPath, srcDir string) error { + // Create a new zip file + zipFile, err := os.Create(zipPath) + if err != nil { + return cosy.WrapErrorWithParams(ErrCreateZipFile, err.Error()) + } + defer zipFile.Close() + + // Create a new zip writer + zipWriter := zip.NewWriter(zipFile) + defer zipWriter.Close() + + // Walk through all files in the source directory + err = filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + // Get relative path + relPath, err := filepath.Rel(srcDir, path) + if err != nil { + return err + } + + // Skip if it's the source directory itself + if relPath == "." { + return nil + } + + // Check if it's a symlink + if info.Mode()&os.ModeSymlink != 0 { + // Get target of symlink + linkTarget, err := os.Readlink(path) + if err != nil { + return cosy.WrapErrorWithParams(ErrReadSymlink, err.Error()) + } + + // Create symlink entry in zip + header := &zip.FileHeader{ + Name: relPath, + Method: zip.Deflate, + } + header.SetMode(info.Mode()) + + writer, err := zipWriter.CreateHeader(header) + if err != nil { + return cosy.WrapErrorWithParams(ErrCreateZipEntry, err.Error()) + } + + // Write link target as content (common way to store symlinks in zip) + _, err = writer.Write([]byte(linkTarget)) + if err != nil { + return cosy.WrapErrorWithParams(ErrCopyContent, relPath) + } + + return nil + } + + // Create zip header + header, err := zip.FileInfoHeader(info) + if err != nil { + return cosy.WrapErrorWithParams(ErrCreateZipHeader, err.Error()) + } + + // Set relative path as name + header.Name = relPath + if info.IsDir() { + header.Name += "/" + } + + // Set compression method + header.Method = zip.Deflate + + // Create zip entry writer + writer, err := zipWriter.CreateHeader(header) + if err != nil { + return cosy.WrapErrorWithParams(ErrCreateZipEntry, err.Error()) + } + + // Skip if it's a directory + if info.IsDir() { + return nil + } + + // Open source file + source, err := os.Open(path) + if err != nil { + return cosy.WrapErrorWithParams(ErrOpenSourceFile, err.Error()) + } + defer source.Close() + + // Copy to zip + _, err = io.Copy(writer, source) + return err + }) + + return err +} + +// createZipArchiveFromFiles creates a zip archive from a list of files +func createZipArchiveFromFiles(zipPath string, files []string) error { + // Create a new zip file + zipFile, err := os.Create(zipPath) + if err != nil { + return cosy.WrapErrorWithParams(ErrCreateZipFile, err.Error()) + } + defer zipFile.Close() + + // Create a new zip writer + zipWriter := zip.NewWriter(zipFile) + defer zipWriter.Close() + + // Add each file to the zip + for _, file := range files { + // Get file info + info, err := os.Stat(file) + if err != nil { + return cosy.WrapErrorWithParams(ErrOpenSourceFile, err.Error()) + } + + // Create zip header + header, err := zip.FileInfoHeader(info) + if err != nil { + return cosy.WrapErrorWithParams(ErrCreateZipHeader, err.Error()) + } + + // Set base name as header name + header.Name = filepath.Base(file) + + // Set compression method + header.Method = zip.Deflate + + // Create zip entry writer + writer, err := zipWriter.CreateHeader(header) + if err != nil { + return cosy.WrapErrorWithParams(ErrCreateZipEntry, err.Error()) + } + + // Open source file + source, err := os.Open(file) + if err != nil { + return cosy.WrapErrorWithParams(ErrOpenSourceFile, err.Error()) + } + defer source.Close() + + // Copy to zip + _, err = io.Copy(writer, source) + if err != nil { + return cosy.WrapErrorWithParams(ErrCopyContent, file) + } + } + + return nil +} + +// calculateFileHash calculates the SHA-256 hash of a file +func calculateFileHash(filePath string) (string, error) { + // Open file + file, err := os.Open(filePath) + if err != nil { + return "", cosy.WrapErrorWithParams(ErrReadFile, filePath) + } + defer file.Close() + + // Create hash + hash := sha256.New() + if _, err := io.Copy(hash, file); err != nil { + return "", cosy.WrapErrorWithParams(ErrCalculateHash, err.Error()) + } + + // Return hex hash + return hex.EncodeToString(hash.Sum(nil)), nil +} + +// createZipArchiveToBuffer creates a zip archive of files in the specified directory +// and writes the zip content to the provided buffer +func createZipArchiveToBuffer(buffer *bytes.Buffer, sourceDir string) error { + // Create a zip writer that writes to the buffer + zipWriter := zip.NewWriter(buffer) + defer zipWriter.Close() + + // Walk through all files in the source directory + err := filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + // Skip the source directory itself + if path == sourceDir { + return nil + } + + // Get the relative path to the source directory + relPath, err := filepath.Rel(sourceDir, path) + if err != nil { + return err + } + + // Check if it's a symlink + if info.Mode()&os.ModeSymlink != 0 { + // Get target of symlink + linkTarget, err := os.Readlink(path) + if err != nil { + return cosy.WrapErrorWithParams(ErrReadSymlink, err.Error()) + } + + // Create symlink entry in zip + header := &zip.FileHeader{ + Name: relPath, + Method: zip.Deflate, + } + header.SetMode(info.Mode()) + + writer, err := zipWriter.CreateHeader(header) + if err != nil { + return cosy.WrapErrorWithParams(ErrCreateZipEntry, err.Error()) + } + + // Write link target as content + _, err = writer.Write([]byte(linkTarget)) + if err != nil { + return cosy.WrapErrorWithParams(ErrCopyContent, relPath) + } + + return nil + } + + // Create a zip header from the file info + header, err := zip.FileInfoHeader(info) + if err != nil { + return cosy.WrapErrorWithParams(ErrCreateZipHeader, err.Error()) + } + + // Set the name to be relative to the source directory + header.Name = relPath + + // Set the compression method + if !info.IsDir() { + header.Method = zip.Deflate + } + + // Create the entry in the zip file + writer, err := zipWriter.CreateHeader(header) + if err != nil { + return cosy.WrapErrorWithParams(ErrCreateZipEntry, err.Error()) + } + + // If it's a directory, we're done + if info.IsDir() { + return nil + } + + // Open the source file + file, err := os.Open(path) + if err != nil { + return cosy.WrapErrorWithParams(ErrOpenSourceFile, err.Error()) + } + defer file.Close() + + // Copy the file contents to the zip entry + _, err = io.Copy(writer, file) + if err != nil { + return cosy.WrapErrorWithParams(ErrCopyContent, relPath) + } + + return nil + }) + + if err != nil { + return err + } + + // Close the zip writer to ensure all data is written + return zipWriter.Close() +} diff --git a/internal/backup/errors.go b/internal/backup/errors.go new file mode 100644 index 00000000..eb842ae4 --- /dev/null +++ b/internal/backup/errors.go @@ -0,0 +1,83 @@ +package backup + +import ( + "github.com/uozi-tech/cosy" +) + +var ( + errScope = cosy.NewErrorScope("backup") + + // Backup errors + ErrCreateTempDir = errScope.New(4002, "Failed to create temporary directory") + ErrCreateTempSubDir = errScope.New(4003, "Failed to create temporary subdirectory") + ErrBackupNginxUI = errScope.New(4004, "Failed to backup Nginx UI files: {0}") + ErrBackupNginx = errScope.New(4005, "Failed to backup Nginx config files: {0}") + ErrCreateHashFile = errScope.New(4006, "Failed to create hash info file: {0}") + ErrEncryptNginxUIDir = errScope.New(4007, "Failed to encrypt Nginx UI directory: {0}") + ErrEncryptNginxDir = errScope.New(4008, "Failed to encrypt Nginx directory: {0}") + ErrCreateZipArchive = errScope.New(4009, "Failed to create zip archive: {0}") + ErrGenerateAESKey = errScope.New(4011, "Failed to generate AES key: {0}") + ErrGenerateIV = errScope.New(4012, "Failed to generate initialization vector: {0}") + ErrCreateBackupFile = errScope.New(4013, "Failed to create backup file: {0}") + ErrCleanupTempDir = errScope.New(4014, "Failed to cleanup temporary directory: {0}") + + // Config and file errors + ErrConfigPathEmpty = errScope.New(4101, "Config path is empty") + ErrCopyConfigFile = errScope.New(4102, "Failed to copy config file: {0}") + ErrCopyDBDir = errScope.New(4103, "Failed to copy database directory: {0}") + ErrCopyDBFile = errScope.New(4104, "Failed to copy database file: {0}") + ErrCalculateHash = errScope.New(4105, "Failed to calculate hash: {0}") + ErrNginxConfigDirEmpty = errScope.New(4106, "Nginx config directory is not set") + ErrCopyNginxConfigDir = errScope.New(4107, "Failed to copy Nginx config directory: {0}") + ErrReadSymlink = errScope.New(4108, "Failed to read symlink: {0}") + + // Encryption and decryption errors + ErrReadFile = errScope.New(4201, "Failed to read file: {0}") + ErrEncryptFile = errScope.New(4202, "Failed to encrypt file: {0}") + ErrWriteEncryptedFile = errScope.New(4203, "Failed to write encrypted file: {0}") + ErrEncryptData = errScope.New(4204, "Failed to encrypt data: {0}") + ErrDecryptData = errScope.New(4205, "Failed to decrypt data: {0}") + ErrInvalidPadding = errScope.New(4206, "Invalid padding in decrypted data") + + // Zip file errors + ErrCreateZipFile = errScope.New(4301, "Failed to create zip file: {0}") + ErrCreateZipEntry = errScope.New(4302, "Failed to create zip entry: {0}") + ErrOpenSourceFile = errScope.New(4303, "Failed to open source file: {0}") + ErrCreateZipHeader = errScope.New(4304, "Failed to create zip header: {0}") + ErrCopyContent = errScope.New(4305, "Failed to copy file content: {0}") + ErrWriteZipBuffer = errScope.New(4306, "Failed to write to zip buffer: {0}") + + // Restore errors + ErrCreateRestoreDir = errScope.New(4501, "Failed to create restore directory: {0}") + ErrExtractArchive = errScope.New(4505, "Failed to extract archive: {0}") + ErrDecryptNginxUIDir = errScope.New(4506, "Failed to decrypt Nginx UI directory: {0}") + ErrDecryptNginxDir = errScope.New(4507, "Failed to decrypt Nginx directory: {0}") + ErrVerifyHashes = errScope.New(4508, "Failed to verify hashes: {0}") + ErrRestoreNginxConfigs = errScope.New(4509, "Failed to restore Nginx configs: {0}") + ErrRestoreNginxUIFiles = errScope.New(4510, "Failed to restore Nginx UI files: {0}") + ErrBackupFileNotFound = errScope.New(4511, "Backup file not found: {0}") + ErrInvalidSecurityToken = errScope.New(4512, "Invalid security token format") + ErrInvalidAESKey = errScope.New(4513, "Invalid AES key format: {0}") + ErrInvalidAESIV = errScope.New(4514, "Invalid AES IV format: {0}") + + // Zip extraction errors + ErrOpenZipFile = errScope.New(4601, "Failed to open zip file: {0}") + ErrCreateDir = errScope.New(4602, "Failed to create directory: {0}") + ErrCreateParentDir = errScope.New(4603, "Failed to create parent directory: {0}") + ErrCreateFile = errScope.New(4604, "Failed to create file: {0}") + ErrOpenZipEntry = errScope.New(4605, "Failed to open zip entry: {0}") + ErrCreateSymlink = errScope.New(4606, "Failed to create symbolic link: {0}") + ErrInvalidFilePath = errScope.New(4607, "Invalid file path: {0}") + ErrEvalSymlinks = errScope.New(4608, "Failed to evaluate symbolic links: {0}") + + // Decryption errors + ErrReadEncryptedFile = errScope.New(4701, "Failed to read encrypted file: {0}") + ErrDecryptFile = errScope.New(4702, "Failed to decrypt file: {0}") + ErrWriteDecryptedFile = errScope.New(4703, "Failed to write decrypted file: {0}") + + // Hash verification errors + ErrReadHashFile = errScope.New(4801, "Failed to read hash info file: {0}") + ErrCalculateUIHash = errScope.New(4802, "Failed to calculate Nginx UI hash: {0}") + ErrCalculateNginxHash = errScope.New(4803, "Failed to calculate Nginx hash: {0}") + ErrHashMismatch = errScope.New(4804, "Hash verification failed: file integrity compromised") +) diff --git a/internal/backup/restore.go b/internal/backup/restore.go new file mode 100644 index 00000000..1d744ec1 --- /dev/null +++ b/internal/backup/restore.go @@ -0,0 +1,369 @@ +package backup + +import ( + "archive/zip" + "io" + "os" + "path/filepath" + "strings" + + "github.com/0xJacky/Nginx-UI/internal/nginx" + "github.com/0xJacky/Nginx-UI/settings" + "github.com/uozi-tech/cosy" + cosysettings "github.com/uozi-tech/cosy/settings" +) + +// RestoreResult contains the results of a restore operation +type RestoreResult struct { + RestoreDir string + NginxUIRestored bool + NginxRestored bool + HashMatch bool +} + +// RestoreOptions contains options for restore operation +type RestoreOptions struct { + BackupPath string + AESKey []byte + AESIv []byte + RestoreDir string + RestoreNginx bool + VerifyHash bool + RestoreNginxUI bool +} + +// Restore restores data from a backup archive +func Restore(options RestoreOptions) (RestoreResult, error) { + // Create restore directory if it doesn't exist + if err := os.MkdirAll(options.RestoreDir, 0755); err != nil { + return RestoreResult{}, cosy.WrapErrorWithParams(ErrCreateRestoreDir, err.Error()) + } + + // Extract main archive to restore directory + if err := extractZipArchive(options.BackupPath, options.RestoreDir); err != nil { + return RestoreResult{}, cosy.WrapErrorWithParams(ErrExtractArchive, err.Error()) + } + + // Decrypt the extracted files + hashInfoPath := filepath.Join(options.RestoreDir, HashInfoFile) + nginxUIZipPath := filepath.Join(options.RestoreDir, NginxUIZipName) + nginxZipPath := filepath.Join(options.RestoreDir, NginxZipName) + + // Decrypt hash info file + if err := decryptFile(hashInfoPath, options.AESKey, options.AESIv); err != nil { + return RestoreResult{}, cosy.WrapErrorWithParams(ErrDecryptFile, HashInfoFile) + } + + // Decrypt nginx-ui.zip + if err := decryptFile(nginxUIZipPath, options.AESKey, options.AESIv); err != nil { + return RestoreResult{}, cosy.WrapErrorWithParams(ErrDecryptNginxUIDir, err.Error()) + } + + // Decrypt nginx.zip + if err := decryptFile(nginxZipPath, options.AESKey, options.AESIv); err != nil { + return RestoreResult{}, cosy.WrapErrorWithParams(ErrDecryptNginxDir, err.Error()) + } + + // Extract zip files to subdirectories + nginxUIDir := filepath.Join(options.RestoreDir, NginxUIDir) + nginxDir := filepath.Join(options.RestoreDir, NginxDir) + + if err := os.MkdirAll(nginxUIDir, 0755); err != nil { + return RestoreResult{}, cosy.WrapErrorWithParams(ErrCreateDir, nginxUIDir) + } + + if err := os.MkdirAll(nginxDir, 0755); err != nil { + return RestoreResult{}, cosy.WrapErrorWithParams(ErrCreateDir, nginxDir) + } + + // Extract nginx-ui.zip to nginx-ui directory + if err := extractZipArchive(nginxUIZipPath, nginxUIDir); err != nil { + return RestoreResult{}, cosy.WrapErrorWithParams(ErrExtractArchive, "nginx-ui.zip") + } + + // Extract nginx.zip to nginx directory + if err := extractZipArchive(nginxZipPath, nginxDir); err != nil { + return RestoreResult{}, cosy.WrapErrorWithParams(ErrExtractArchive, "nginx.zip") + } + + result := RestoreResult{ + RestoreDir: options.RestoreDir, + NginxUIRestored: false, + NginxRestored: false, + HashMatch: false, + } + + // Verify hashes if requested + if options.VerifyHash { + hashMatch, err := verifyHashes(options.RestoreDir, nginxUIZipPath, nginxZipPath) + if err != nil { + return result, cosy.WrapErrorWithParams(ErrVerifyHashes, err.Error()) + } + result.HashMatch = hashMatch + } + + // Restore nginx configs if requested + if options.RestoreNginx { + if err := restoreNginxConfigs(nginxDir); err != nil { + return result, cosy.WrapErrorWithParams(ErrRestoreNginxConfigs, err.Error()) + } + result.NginxRestored = true + } + + // Restore nginx-ui config if requested + if options.RestoreNginxUI { + if err := restoreNginxUIConfig(nginxUIDir); err != nil { + return result, cosy.WrapErrorWithParams(ErrBackupNginxUI, err.Error()) + } + result.NginxUIRestored = true + } + + return result, nil +} + +// extractZipArchive extracts a zip archive to the specified directory +func extractZipArchive(zipPath, destDir string) error { + reader, err := zip.OpenReader(zipPath) + if err != nil { + return cosy.WrapErrorWithParams(ErrOpenZipFile, err.Error()) + } + defer reader.Close() + + for _, file := range reader.File { + err := extractZipFile(file, destDir) + if err != nil { + return err + } + } + + return nil +} + +// extractZipFile extracts a single file from a zip archive +func extractZipFile(file *zip.File, destDir string) error { + // Check for directory traversal elements in the file name + if strings.Contains(file.Name, "..") { + return cosy.WrapErrorWithParams(ErrInvalidFilePath, file.Name) + } + + // Create directory path if needed + filePath := filepath.Join(destDir, file.Name) + + // Ensure the resulting file path is within the destination directory + destDirAbs, err := filepath.Abs(destDir) + if err != nil { + return cosy.WrapErrorWithParams(ErrInvalidFilePath, "cannot resolve destination path") + } + + filePathAbs, err := filepath.Abs(filePath) + if err != nil { + return cosy.WrapErrorWithParams(ErrInvalidFilePath, file.Name) + } + + if !strings.HasPrefix(filePathAbs, destDirAbs+string(os.PathSeparator)) { + return cosy.WrapErrorWithParams(ErrInvalidFilePath, file.Name) + } + + if file.FileInfo().IsDir() { + if err := os.MkdirAll(filePath, file.Mode()); err != nil { + return cosy.WrapErrorWithParams(ErrCreateDir, filePath) + } + return nil + } + + // Create parent directory if needed + if err := os.MkdirAll(filepath.Dir(filePath), 0755); err != nil { + return cosy.WrapErrorWithParams(ErrCreateParentDir, filePath) + } + + // Check if this is a symlink by examining mode bits + if file.Mode()&os.ModeSymlink != 0 { + // Open source file in zip to read the link target + srcFile, err := file.Open() + if err != nil { + return cosy.WrapErrorWithParams(ErrOpenZipEntry, file.Name) + } + defer srcFile.Close() + + // Read the link target + linkTargetBytes, err := io.ReadAll(srcFile) + if err != nil { + return cosy.WrapErrorWithParams(ErrReadSymlink, file.Name) + } + linkTarget := string(linkTargetBytes) + + // Verify the link target doesn't escape the destination directory + absLinkTarget := filepath.Clean(filepath.Join(filepath.Dir(filePath), linkTarget)) + if !strings.HasPrefix(absLinkTarget, destDirAbs+string(os.PathSeparator)) { + return cosy.WrapErrorWithParams(ErrInvalidFilePath, linkTarget) + } + + // Remove any existing file/link at the target path + _ = os.Remove(filePath) + + // Create the symlink + if err := os.Symlink(linkTarget, filePath); err != nil { + return cosy.WrapErrorWithParams(ErrCreateSymlink, file.Name) + } + + // Verify the resolved symlink path is within destination directory + resolvedPath, err := filepath.EvalSymlinks(filePath) + if err != nil { + return cosy.WrapErrorWithParams(ErrEvalSymlinks, filePath) + } + + resolvedPathAbs, err := filepath.Abs(resolvedPath) + if err != nil { + return cosy.WrapErrorWithParams(ErrInvalidFilePath, resolvedPath) + } + + if !strings.HasPrefix(resolvedPathAbs, destDirAbs+string(os.PathSeparator)) { + // Remove the symlink if it points outside the destination directory + _ = os.Remove(filePath) + return cosy.WrapErrorWithParams(ErrInvalidFilePath, resolvedPath) + } + + return nil + } + + // Create file + destFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode()) + if err != nil { + return cosy.WrapErrorWithParams(ErrCreateFile, filePath) + } + defer destFile.Close() + + // Open source file in zip + srcFile, err := file.Open() + if err != nil { + return cosy.WrapErrorWithParams(ErrOpenZipEntry, file.Name) + } + defer srcFile.Close() + + // Copy content + if _, err := io.Copy(destFile, srcFile); err != nil { + return cosy.WrapErrorWithParams(ErrCopyContent, file.Name) + } + + return nil +} + +// verifyHashes verifies the hashes of the extracted zip files +func verifyHashes(restoreDir, nginxUIZipPath, nginxZipPath string) (bool, error) { + hashFile := filepath.Join(restoreDir, HashInfoFile) + hashContent, err := os.ReadFile(hashFile) + if err != nil { + return false, cosy.WrapErrorWithParams(ErrReadHashFile, err.Error()) + } + + hashInfo := parseHashInfo(string(hashContent)) + + // Calculate hash for nginx-ui.zip + nginxUIHash, err := calculateFileHash(nginxUIZipPath) + if err != nil { + return false, cosy.WrapErrorWithParams(ErrCalculateUIHash, err.Error()) + } + + // Calculate hash for nginx.zip + nginxHash, err := calculateFileHash(nginxZipPath) + if err != nil { + return false, cosy.WrapErrorWithParams(ErrCalculateNginxHash, err.Error()) + } + + // Verify hashes + return (hashInfo.NginxUIHash == nginxUIHash && hashInfo.NginxHash == nginxHash), nil +} + +// parseHashInfo parses hash info from content string +func parseHashInfo(content string) HashInfo { + info := HashInfo{} + lines := strings.Split(content, "\n") + + for _, line := range lines { + line = strings.TrimSpace(line) + if line == "" { + continue + } + + parts := strings.SplitN(line, ":", 2) + if len(parts) != 2 { + continue + } + + key := strings.TrimSpace(parts[0]) + value := strings.TrimSpace(parts[1]) + + switch key { + case "nginx-ui_hash": + info.NginxUIHash = value + case "nginx_hash": + info.NginxHash = value + case "timestamp": + info.Timestamp = value + case "version": + info.Version = value + } + } + + return info +} + +// restoreNginxConfigs restores nginx configuration files +func restoreNginxConfigs(nginxBackupDir string) error { + destDir := nginx.GetConfPath() + if destDir == "" { + return ErrNginxConfigDirEmpty + } + + // Remove all contents in the destination directory first + // Read directory entries + entries, err := os.ReadDir(destDir) + if err != nil { + return cosy.WrapErrorWithParams(ErrCopyNginxConfigDir, "failed to read directory: "+err.Error()) + } + + // Remove each entry + for _, entry := range entries { + entryPath := filepath.Join(destDir, entry.Name()) + err := os.RemoveAll(entryPath) + if err != nil { + return cosy.WrapErrorWithParams(ErrCopyNginxConfigDir, "failed to remove: "+err.Error()) + } + } + + // Copy files from backup to nginx config directory + if err := copyDirectory(nginxBackupDir, destDir); err != nil { + return err + } + + return nil +} + +// restoreNginxUIConfig restores nginx-ui configuration files +func restoreNginxUIConfig(nginxUIBackupDir string) error { + // Get config directory + configDir := filepath.Dir(cosysettings.ConfPath) + if configDir == "" { + return ErrConfigPathEmpty + } + + // Restore app.ini to the configured location + srcConfigPath := filepath.Join(nginxUIBackupDir, "app.ini") + if err := copyFile(srcConfigPath, cosysettings.ConfPath); err != nil { + return err + } + + // Restore database file if exists + dbName := settings.DatabaseSettings.GetName() + srcDBPath := filepath.Join(nginxUIBackupDir, dbName+".db") + destDBPath := filepath.Join(configDir, dbName+".db") + + // Only attempt to copy if database file exists in backup + if _, err := os.Stat(srcDBPath); err == nil { + if err := copyFile(srcDBPath, destDBPath); err != nil { + return err + } + } + + return nil +} diff --git a/internal/backup/utils.go b/internal/backup/utils.go new file mode 100644 index 00000000..44dd0a38 --- /dev/null +++ b/internal/backup/utils.go @@ -0,0 +1,85 @@ +package backup + +import ( + "io" + "os" + "path/filepath" + + "github.com/uozi-tech/cosy" +) + +// copyFile copies a file from src to dst +func copyFile(src, dst string) error { + // Open source file + source, err := os.Open(src) + if err != nil { + return err + } + defer source.Close() + + // Create destination file + destination, err := os.Create(dst) + if err != nil { + return err + } + defer destination.Close() + + // Copy content + _, err = io.Copy(destination, source) + return err +} + +// copyDirectory copies a directory recursively from src to dst +func copyDirectory(src, dst string) error { + // Check if source is a directory + srcInfo, err := os.Stat(src) + if err != nil { + return err + } + if !srcInfo.IsDir() { + return cosy.WrapErrorWithParams(ErrCopyNginxConfigDir, "%s is not a directory", src) + } + + // Create destination directory + if err := os.MkdirAll(dst, srcInfo.Mode()); err != nil { + return err + } + + // Walk through source directory + return filepath.Walk(src, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + // Calculate relative path + relPath, err := filepath.Rel(src, path) + if err != nil { + return err + } + if relPath == "." { + return nil + } + + // Create target path + targetPath := filepath.Join(dst, relPath) + + // Check if it's a symlink + if info.Mode()&os.ModeSymlink != 0 { + // Read the link + linkTarget, err := os.Readlink(path) + if err != nil { + return err + } + // Create symlink at target path + return os.Symlink(linkTarget, targetPath) + } + + // If it's a directory, create it + if info.IsDir() { + return os.MkdirAll(targetPath, info.Mode()) + } + + // If it's a file, copy it + return copyFile(path, targetPath) + }) +} diff --git a/internal/backup/version_test.go b/internal/backup/version_test.go new file mode 100644 index 00000000..009d32f0 --- /dev/null +++ b/internal/backup/version_test.go @@ -0,0 +1,117 @@ +package backup + +import ( + "os" + "path/filepath" + "strings" + "testing" + + "github.com/0xJacky/Nginx-UI/internal/version" + "github.com/0xJacky/Nginx-UI/settings" + "github.com/stretchr/testify/assert" + cosysettings "github.com/uozi-tech/cosy/settings" +) + +// TestBackupVersion verifies that the backup file contains correct version information +func TestBackupVersion(t *testing.T) { + // Make sure backup files are cleaned up at the start and end of the test + cleanupBackupFiles() + defer cleanupBackupFiles() + + // Create test configuration + tempDir, err := os.MkdirTemp("", "nginx-ui-backup-version-test-*") + assert.NoError(t, err) + defer os.RemoveAll(tempDir) + + // Create config file + configPath := filepath.Join(tempDir, "config.ini") + testConfig := []byte("[app]\nName = Nginx UI Test\n") + err = os.WriteFile(configPath, testConfig, 0644) + assert.NoError(t, err) + + // Create database file + dbName := settings.DatabaseSettings.GetName() + dbFile := dbName + ".db" + dbPath := filepath.Join(tempDir, dbFile) + testDB := []byte("CREATE TABLE users (id INT, name TEXT);") + err = os.WriteFile(dbPath, testDB, 0644) + assert.NoError(t, err) + + // Create nginx directory + nginxConfigDir := filepath.Join(tempDir, "nginx") + err = os.MkdirAll(nginxConfigDir, 0755) + assert.NoError(t, err) + + // Create nginx config + testNginxContent := []byte("server {\n listen 80;\n server_name example.com;\n}\n") + err = os.WriteFile(filepath.Join(nginxConfigDir, "nginx.conf"), testNginxContent, 0644) + assert.NoError(t, err) + + // Setup test environment + originalConfPath := cosysettings.ConfPath + originalNginxConfigDir := settings.NginxSettings.ConfigDir + + cosysettings.ConfPath = configPath + settings.NginxSettings.ConfigDir = nginxConfigDir + + // Restore original settings after test + defer func() { + cosysettings.ConfPath = originalConfPath + settings.NginxSettings.ConfigDir = originalNginxConfigDir + }() + + // Run backup + result, err := Backup() + assert.NoError(t, err) + assert.NotEmpty(t, result.BackupContent) + assert.NotEmpty(t, result.BackupName) + assert.NotEmpty(t, result.AESKey) + assert.NotEmpty(t, result.AESIv) + + // Save backup content to temporary file for restore testing + backupFile := filepath.Join(tempDir, result.BackupName) + err = os.WriteFile(backupFile, result.BackupContent, 0644) + assert.NoError(t, err) + + // Decode AES key and IV + key, err := DecodeFromBase64(result.AESKey) + assert.NoError(t, err) + iv, err := DecodeFromBase64(result.AESIv) + assert.NoError(t, err) + + // Use the Restore function to extract and verify + restoreDir, err := os.MkdirTemp("", "nginx-ui-restore-version-test-*") + assert.NoError(t, err) + defer os.RemoveAll(restoreDir) + + restoreResult, err := Restore(RestoreOptions{ + BackupPath: backupFile, + AESKey: key, + AESIv: iv, + RestoreDir: restoreDir, + VerifyHash: true, + RestoreNginx: false, + RestoreNginxUI: false, + }) + assert.NoError(t, err) + assert.True(t, restoreResult.HashMatch, "Hash should match") + + // Check hash_info.txt file + hashInfoPath := filepath.Join(restoreDir, HashInfoFile) + hashInfoContent, err := os.ReadFile(hashInfoPath) + assert.NoError(t, err) + + // Verify version information + versionInfo := version.GetVersionInfo() + expectedVersion := versionInfo.Version + + // Check if hash_info.txt contains version info + hashInfoStr := string(hashInfoContent) + t.Logf("Hash info content: %s", hashInfoStr) + + assert.True(t, strings.Contains(hashInfoStr, "version: "), "Hash info should contain version field") + + // Parse hash_info.txt content + info := parseHashInfo(hashInfoStr) + assert.Equal(t, expectedVersion, info.Version, "Backup version should match current version") +} diff --git a/query/notifications.gen.go b/query/notifications.gen.go index ac860557..e0a066ec 100644 --- a/query/notifications.gen.go +++ b/query/notifications.gen.go @@ -34,7 +34,8 @@ func newNotification(db *gorm.DB, opts ...gen.DOOption) notification { _notification.DeletedAt = field.NewField(tableName, "deleted_at") _notification.Type = field.NewInt(tableName, "type") _notification.Title = field.NewString(tableName, "title") - _notification.Details = field.NewString(tableName, "details") + _notification.Content = field.NewString(tableName, "content") + _notification.Details = field.NewField(tableName, "details") _notification.fillFieldMap() @@ -51,7 +52,8 @@ type notification struct { DeletedAt field.Field Type field.Int Title field.String - Details field.String + Content field.String + Details field.Field fieldMap map[string]field.Expr } @@ -74,7 +76,8 @@ func (n *notification) updateTableName(table string) *notification { n.DeletedAt = field.NewField(table, "deleted_at") n.Type = field.NewInt(table, "type") n.Title = field.NewString(table, "title") - n.Details = field.NewString(table, "details") + n.Content = field.NewString(table, "content") + n.Details = field.NewField(table, "details") n.fillFieldMap() @@ -91,13 +94,14 @@ func (n *notification) GetFieldByName(fieldName string) (field.OrderExpr, bool) } func (n *notification) fillFieldMap() { - n.fieldMap = make(map[string]field.Expr, 7) + n.fieldMap = make(map[string]field.Expr, 8) n.fieldMap["id"] = n.ID n.fieldMap["created_at"] = n.CreatedAt n.fieldMap["updated_at"] = n.UpdatedAt n.fieldMap["deleted_at"] = n.DeletedAt n.fieldMap["type"] = n.Type n.fieldMap["title"] = n.Title + n.fieldMap["content"] = n.Content n.fieldMap["details"] = n.Details } diff --git a/query/site_categories.gen.go b/query/site_categories.gen.go index 8b0898cd..d868679e 100644 --- a/query/site_categories.gen.go +++ b/query/site_categories.gen.go @@ -34,6 +34,7 @@ func newSiteCategory(db *gorm.DB, opts ...gen.DOOption) siteCategory { _siteCategory.DeletedAt = field.NewField(tableName, "deleted_at") _siteCategory.Name = field.NewString(tableName, "name") _siteCategory.SyncNodeIds = field.NewField(tableName, "sync_node_ids") + _siteCategory.OrderID = field.NewInt(tableName, "order_id") _siteCategory.fillFieldMap() @@ -50,6 +51,7 @@ type siteCategory struct { DeletedAt field.Field Name field.String SyncNodeIds field.Field + OrderID field.Int fieldMap map[string]field.Expr } @@ -72,6 +74,7 @@ func (s *siteCategory) updateTableName(table string) *siteCategory { s.DeletedAt = field.NewField(table, "deleted_at") s.Name = field.NewString(table, "name") s.SyncNodeIds = field.NewField(table, "sync_node_ids") + s.OrderID = field.NewInt(table, "order_id") s.fillFieldMap() @@ -88,13 +91,14 @@ func (s *siteCategory) GetFieldByName(fieldName string) (field.OrderExpr, bool) } func (s *siteCategory) fillFieldMap() { - s.fieldMap = make(map[string]field.Expr, 6) + s.fieldMap = make(map[string]field.Expr, 7) s.fieldMap["id"] = s.ID s.fieldMap["created_at"] = s.CreatedAt s.fieldMap["updated_at"] = s.UpdatedAt s.fieldMap["deleted_at"] = s.DeletedAt s.fieldMap["name"] = s.Name s.fieldMap["sync_node_ids"] = s.SyncNodeIds + s.fieldMap["order_id"] = s.OrderID } func (s siteCategory) clone(db *gorm.DB) siteCategory { diff --git a/settings/settings.go b/settings/settings.go index 675ea2aa..b2df2b47 100644 --- a/settings/settings.go +++ b/settings/settings.go @@ -1,14 +1,15 @@ package settings import ( - "github.com/caarlos0/env/v11" - "github.com/elliotchance/orderedmap/v3" - "github.com/spf13/cast" - "github.com/uozi-tech/cosy/settings" "log" "os" "strings" "time" + + "github.com/caarlos0/env/v11" + "github.com/elliotchance/orderedmap/v3" + "github.com/spf13/cast" + "github.com/uozi-tech/cosy/settings" ) var (