From 1b53cd4ca8edd0b68fad66473fafe2fb35072045 Mon Sep 17 00:00:00 2001
From: CityFun <31820853+zhengkunwang223@users.noreply.github.com>
Date: Tue, 28 Oct 2025 18:18:18 +0800
Subject: [PATCH] feat: add sync waf ip group cron job (#10802)
Refs https://github.com/1Panel-dev/1Panel/issues/8915
---
agent/app/service/cronjob_helper.go | 74 +++++++++++++++++++
frontend/src/lang/modules/en.ts | 1 +
frontend/src/lang/modules/es-es.ts | 2 +
frontend/src/lang/modules/ja.ts | 1 +
frontend/src/lang/modules/ko.ts | 2 +
frontend/src/lang/modules/ms.ts | 1 +
frontend/src/lang/modules/pt-br.ts | 1 +
frontend/src/lang/modules/ru.ts | 1 +
frontend/src/lang/modules/tr.ts | 1 +
frontend/src/lang/modules/zh-Hant.ts | 1 +
frontend/src/lang/modules/zh.ts | 1 +
.../views/cronjob/cronjob/operate/index.vue | 1 +
12 files changed, 87 insertions(+)
diff --git a/agent/app/service/cronjob_helper.go b/agent/app/service/cronjob_helper.go
index 3293e2966..39ac44c56 100644
--- a/agent/app/service/cronjob_helper.go
+++ b/agent/app/service/cronjob_helper.go
@@ -1,11 +1,15 @@
package service
import (
+ "bufio"
"context"
"fmt"
+ "io"
+ "net/http"
"os"
"path"
pathUtils "path"
+ "path/filepath"
"strings"
"time"
@@ -127,6 +131,8 @@ func (u *CronjobService) loadTask(cronjob *model.Cronjob, record *model.JobRecor
err = u.handleDirectory(*cronjob, record.StartTime, taskItem)
case "log":
err = u.handleSystemLog(*cronjob, record.StartTime, taskItem)
+ case "syncIpGroup":
+ u.handleSyncIpGroup(*cronjob, taskItem)
}
return err
}
@@ -210,6 +216,74 @@ func (u *CronjobService) handleNtpSync(cronjob model.Cronjob, taskItem *task.Tas
}, nil, int(cronjob.RetryTimes), time.Duration(cronjob.Timeout)*time.Second)
}
+func (u *CronjobService) handleSyncIpGroup(cronjob model.Cronjob, taskItem *task.Task) {
+ taskItem.AddSubTaskWithOps(i18n.GetWithName("SyncIpGroup", cronjob.Name), func(t *task.Task) error {
+ appInstall, err := getAppInstallByKey(constant.AppOpenresty)
+ if err != nil {
+ return err
+ }
+ ipGroupDir := path.Join(appInstall.GetPath(), "1pwaf", "data", "rules", "ip_group")
+ urlDir := path.Join(ipGroupDir, "ip_group_url")
+
+ urlsFiles, err := os.ReadDir(urlDir)
+ if err != nil {
+ return err
+ }
+ for _, file := range urlsFiles {
+ if file.IsDir() || !strings.HasSuffix(file.Name(), "_url") {
+ continue
+ }
+ urlFilePath := filepath.Join(urlDir, file.Name())
+
+ urlContent, err := os.ReadFile(urlFilePath)
+ if err != nil {
+ continue
+ }
+ remoteURL := strings.TrimSpace(string(urlContent))
+ if remoteURL == "" {
+ continue
+ }
+ resp, err := http.Get(remoteURL)
+ if err != nil {
+ continue
+ }
+
+ ipGroupFile := strings.TrimSuffix(file.Name(), "_url")
+ ipGroupPath := filepath.Join(ipGroupDir, ipGroupFile)
+
+ if resp.StatusCode != http.StatusOK {
+ resp.Body.Close()
+ taskItem.Logf("get remote ip group %s failed %s status code %d", ipGroupFile, remoteURL, resp.StatusCode)
+ continue
+ }
+
+ outFile, err := os.OpenFile(ipGroupPath, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
+ if err != nil {
+ resp.Body.Close()
+ taskItem.Logf("sync %s failed %v", ipGroupFile, err)
+ continue
+ }
+
+ writer := bufio.NewWriter(outFile)
+ _, err = io.Copy(writer, resp.Body)
+ if err != nil {
+ outFile.Close()
+ resp.Body.Close()
+ taskItem.Logf("sync %s failed , write file failed %v", ipGroupFile, err)
+ continue
+ }
+ writer.Flush()
+ outFile.Close()
+ resp.Body.Close()
+ taskItem.LogSuccess(i18n.Get("TaskSync") + " " + ipGroupFile)
+ }
+ if err := opNginx(appInstall.ContainerName, constant.NginxReload); err != nil {
+ return err
+ }
+ return nil
+ }, nil, int(cronjob.RetryTimes), time.Duration(cronjob.Timeout)*time.Second)
+}
+
func (u *CronjobService) handleCutWebsiteLog(cronjob *model.Cronjob, startTime time.Time, taskItem *task.Task) error {
clientMap := NewBackupClientMap([]string{fmt.Sprintf("%v", cronjob.DownloadAccountID)})
if !clientMap[fmt.Sprintf("%d", cronjob.DownloadAccountID)].isOk {
diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts
index 6bf4403c9..7e2c90a76 100644
--- a/frontend/src/lang/modules/en.ts
+++ b/frontend/src/lang/modules/en.ts
@@ -1142,6 +1142,7 @@ const message = {
errPath: 'Backup path [{0}] error, cannot download!',
cutWebsiteLog: 'Website log rotation',
cutWebsiteLogHelper: 'The rotated log files will be backed up to the backup directory of 1Panel.',
+ syncIpGroup: 'Sync WAF IP groups',
requestExpirationTime: 'Upload request expiration time(Hours)',
unitHours: 'Unit: Hours',
diff --git a/frontend/src/lang/modules/es-es.ts b/frontend/src/lang/modules/es-es.ts
index fed87bdf1..f5ea2eb9f 100644
--- a/frontend/src/lang/modules/es-es.ts
+++ b/frontend/src/lang/modules/es-es.ts
@@ -1144,6 +1144,8 @@ const message = {
errPath: '¡Error en la ruta de respaldo [{0}], no se puede descargar!',
cutWebsiteLog: 'Rotación de logs del sitio',
cutWebsiteLogHelper: 'Los archivos de log rotados se respaldarán en el directorio de respaldos de 1Panel.',
+ syncIpGroup: 'Sincronizar grupos de IP de WAF',
+
requestExpirationTime: 'Tiempo de expiración de solicitud de subida (Horas)',
unitHours: 'Unidad: Horas',
alertTitle: 'Tarea programada - {0} 「{1}」 Alerta de fallo',
diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts
index 6f1475b3a..a2cf382a9 100644
--- a/frontend/src/lang/modules/ja.ts
+++ b/frontend/src/lang/modules/ja.ts
@@ -1104,6 +1104,7 @@ const message = {
errPath: 'バックアップパス[{0}]エラー、ダウンロードできません!',
cutWebsiteLog: 'ウェブサイトのログローテーション',
cutWebsiteLogHelper: '回転したログファイルは、1パネルのバックアップディレクトリにバックアップされます。',
+ syncIpGroup: 'WAF IP グループを同期',
requestExpirationTime: 'リクエストの有効期限(時間)のアップロード',
unitHours: 'ユニット:時間',
diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts
index 4dbc1b032..4c69f6766 100644
--- a/frontend/src/lang/modules/ko.ts
+++ b/frontend/src/lang/modules/ko.ts
@@ -1098,6 +1098,8 @@ const message = {
errPath: '백업 경로 [{0}] 오류, 다운로드할 수 없습니다!',
cutWebsiteLog: '웹사이트 로그 회전',
cutWebsiteLogHelper: '회전된 로그 파일은 1Panel 의 백업 디렉토리로 백업됩니다.',
+ syncIpGroup: 'WAF IP 그룹 동기화',
+
requestExpirationTime: '업로드 요청 만료 시간(시간)',
unitHours: '단위: 시간',
alertTitle: '예정된 작업 - {0} 「{1}」 작업 실패 경고',
diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts
index 1da22f759..e858b152d 100644
--- a/frontend/src/lang/modules/ms.ts
+++ b/frontend/src/lang/modules/ms.ts
@@ -1135,6 +1135,7 @@ const message = {
errPath: 'Laluan sandaran [{0}] salah, tidak boleh dimuat turun!',
cutWebsiteLog: 'Putaran log laman web',
cutWebsiteLogHelper: 'Fail log yang diputar akan disandarkan ke direktori sandaran 1Panel.',
+ syncIpGroup: 'Segerakkan kumpulan IP WAF',
requestExpirationTime: 'Waktu luput permintaan muat naik (Jam)',
unitHours: 'Unit: Jam',
diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts
index 800a9cdeb..7ee2f1150 100644
--- a/frontend/src/lang/modules/pt-br.ts
+++ b/frontend/src/lang/modules/pt-br.ts
@@ -1127,6 +1127,7 @@ const message = {
errPath: 'Caminho de backup [{0}] com erro, não é possível fazer o download!',
cutWebsiteLog: 'Rotação de log do site',
cutWebsiteLogHelper: 'Os arquivos de log rotacionados serão salvos no diretório de backup do 1Panel.',
+ syncIpGroup: 'Sincronizar grupos de IP do WAF',
requestExpirationTime: 'Tempo de expiração da solicitação de upload (Horas)',
unitHours: 'Unidade: Horas',
diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts
index 712c38b55..1d1831629 100644
--- a/frontend/src/lang/modules/ru.ts
+++ b/frontend/src/lang/modules/ru.ts
@@ -1131,6 +1131,7 @@ const message = {
errPath: 'Ошибка пути резервной копии [{0}], невозможно скачать!',
cutWebsiteLog: 'Ротация логов сайта',
cutWebsiteLogHelper: 'Ротированные файлы логов будут сохранены в директории резервных копий 1Panel.',
+ syncIpGroup: 'Синхронизировать группы IP WAF',
requestExpirationTime: 'Время истечения запроса на загрузку (часы)',
unitHours: 'Единица: часы',
diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts
index b5a921d3f..d363ce7bf 100644
--- a/frontend/src/lang/modules/tr.ts
+++ b/frontend/src/lang/modules/tr.ts
@@ -1154,6 +1154,7 @@ const message = {
errPath: 'Yedek yolu [{0}] hatası, indirilemez!',
cutWebsiteLog: 'Website log döndürme',
cutWebsiteLogHelper: 'Döndürülen log dosyaları 1Panel yedek dizinine yedeklenecektir.',
+ syncIpGroup: 'WAF IP gruplarını senkronize et',
requestExpirationTime: 'Yükleme isteği son kullanma süresi(Saat)',
unitHours: 'Birim: Saat',
diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts
index 50332bece..a40898685 100644
--- a/frontend/src/lang/modules/zh-Hant.ts
+++ b/frontend/src/lang/modules/zh-Hant.ts
@@ -1082,6 +1082,7 @@ const message = {
errPath: '備份路徑 [{0}] 錯誤,無法下載!',
cutWebsiteLog: '切割網站日誌',
cutWebsiteLogHelper: '切割的日誌檔案會備份到 1Panel 的 backup 目錄下',
+ syncIpGroup: '同步 WAF IP 組',
requestExpirationTime: '上傳請求過期時間(小時)',
unitHours: '單位:小時',
diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts
index dd36032cc..46409e9af 100644
--- a/frontend/src/lang/modules/zh.ts
+++ b/frontend/src/lang/modules/zh.ts
@@ -1083,6 +1083,7 @@ const message = {
errPath: '备份路径 [{0}] 错误,无法下载!',
cutWebsiteLog: '切割网站日志',
cutWebsiteLogHelper: '切割的日志文件会备份到 1Panel 的 backup 目录下',
+ syncIpGroup: '同步 WAF IP 组',
requestExpirationTime: '上传请求过期时间(小时)',
unitHours: '单位:小时',
diff --git a/frontend/src/views/cronjob/cronjob/operate/index.vue b/frontend/src/views/cronjob/cronjob/operate/index.vue
index 416a990f3..5578ad58b 100644
--- a/frontend/src/views/cronjob/cronjob/operate/index.vue
+++ b/frontend/src/views/cronjob/cronjob/operate/index.vue
@@ -26,6 +26,7 @@