Browse Source

feat: 删除旧版本 WAF 配置 (#4327)

pull/4331/head
zhengkunwang 8 months ago committed by GitHub
parent
commit
6b244b2b03
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 63
      backend/app/api/v1/website.go
  2. 72
      backend/app/service/website.go
  3. 4
      backend/router/ro_website.go
  4. 212
      cmd/server/docs/docs.go
  5. 208
      cmd/server/docs/swagger.json
  6. 133
      cmd/server/docs/swagger.yaml
  7. 16
      cmd/server/nginx_conf/website_default.conf
  8. 23
      frontend/src/api/interface/website.ts
  9. 12
      frontend/src/api/modules/website.ts
  10. 4
      frontend/src/views/website/website/config/index.vue
  11. 129
      frontend/src/views/website/website/config/safety/ccdeny/index.vue
  12. 134
      frontend/src/views/website/website/config/safety/file-block-list/index.vue
  13. 74
      frontend/src/views/website/website/config/safety/index.vue
  14. 181
      frontend/src/views/website/website/config/safety/simple-list/index.vue
  15. 184
      frontend/src/views/website/website/config/safety/value-list/index.vue
  16. 10
      frontend/src/views/website/website/index.vue

63
backend/app/api/v1/website.go

@ -305,69 +305,6 @@ func (b *BaseApi) CreateWebsiteCheck(c *gin.Context) {
helper.SuccessWithData(c, data)
}
// @Tags Website WAF
// @Summary Load websit waf conf
// @Description 获取网站 waf 配置
// @Accept json
// @Param request body request.WebsiteWafReq true "request"
// @Success 200 {object} response.WebsiteWafConfig
// @Security ApiKeyAuth
// @Router /websites/waf/config [post]
func (b *BaseApi) GetWebsiteWafConfig(c *gin.Context) {
var req request.WebsiteWafReq
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
data, err := websiteService.GetWafConfig(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}
// @Tags Website WAF
// @Summary Update website waf conf
// @Description 更新 网站 waf 配置
// @Accept json
// @Param request body request.WebsiteWafUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/waf/update [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"WAF 配置修改 [domain]","formatEN":"WAF conf update [domain]"}
func (b *BaseApi) UpdateWebsiteWafConfig(c *gin.Context) {
var req request.WebsiteWafUpdate
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := websiteService.UpdateWafConfig(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Website WAF
// @Summary Update website waf file
// @Description 更新 网站 waf 配置文件
// @Accept json
// @Param request body request.WebsiteWafUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/waf/file/update [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"WAF 配置文件修改 [domain]","formatEN":"WAF conf file update [domain]"}
func (b *BaseApi) UpdateWebsiteWafFile(c *gin.Context) {
var req request.WebsiteWafFileUpdate
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := websiteService.UpdateWafFile(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Website Nginx
// @Summary Update website nginx conf
// @Description 更新 网站 nginx 配置

72
backend/app/service/website.go

@ -75,10 +75,6 @@ type IWebsiteService interface {
ChangeDefaultServer(id uint) error
PreInstallCheck(req request.WebsiteInstallCheckReq) ([]response.WebsitePreInstallCheck, error)
GetWafConfig(req request.WebsiteWafReq) (response.WebsiteWafConfig, error)
UpdateWafConfig(req request.WebsiteWafUpdate) error
UpdateWafFile(req request.WebsiteWafFileUpdate) (err error)
GetPHPConfig(id uint) (*response.PHPConfig, error)
UpdatePHPConfig(req request.WebsitePHPConfigUpdate) error
UpdatePHPConfigFile(req request.WebsitePHPFileUpdate) error
@ -327,7 +323,6 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
case constant.RuntimeNode:
website.Proxy = fmt.Sprintf("127.0.0.1:%d", runtime.Port)
}
}
if err = configDefaultNginx(website, domains, appInstall, runtime); err != nil {
@ -852,56 +847,6 @@ func (w WebsiteService) PreInstallCheck(req request.WebsiteInstallCheckReq) ([]r
return nil, nil
}
func (w WebsiteService) GetWafConfig(req request.WebsiteWafReq) (response.WebsiteWafConfig, error) {
var res response.WebsiteWafConfig
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
if err != nil {
return res, nil
}
res.Enable = true
if req.Key != "" {
params, err := getNginxParamsByKeys(constant.NginxScopeServer, []string{"set"}, &website)
if err != nil {
return res, nil
}
for _, param := range params {
if param.Params[0] == req.Key {
res.Enable = len(param.Params) > 1 && param.Params[1] == "on"
break
}
}
}
nginxFull, err := getNginxFull(&website)
if err != nil {
return res, nil
}
filePath := path.Join(nginxFull.SiteDir, "sites", website.Alias, "waf", "rules", req.Rule+".json")
content, err := os.ReadFile(filePath)
if err != nil {
return res, nil
}
res.Content = string(content)
return res, nil
}
func (w WebsiteService) UpdateWafConfig(req request.WebsiteWafUpdate) error {
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
if err != nil {
return err
}
updateValue := "on"
if !req.Enable {
updateValue = "off"
}
return updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{
{Name: "set", Params: []string{req.Key, updateValue}},
}, &website)
}
func (w WebsiteService) UpdateNginxConfigFile(req request.WebsiteNginxUpdate) error {
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
if err != nil {
@ -2339,23 +2284,6 @@ func (w WebsiteService) UpdateRedirectFile(req request.NginxRedirectUpdate) (err
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
}
func (w WebsiteService) UpdateWafFile(req request.WebsiteWafFileUpdate) (err error) {
var (
website model.Website
nginxInstall model.AppInstall
)
website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
if err != nil {
return err
}
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return
}
rulePath := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "waf", "rules", fmt.Sprintf("%s.json", req.Type))
return files.NewFileOp().WriteFile(rulePath, strings.NewReader(req.Content), 0755)
}
func (w WebsiteService) LoadWebsiteDirConfig(req request.WebsiteCommonReq) (*response.WebsiteDirConfig, error) {
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
if err != nil {

4
backend/router/ro_website.go

@ -39,10 +39,6 @@ func (a *WebsiteRouter) InitRouter(Router *gin.RouterGroup) {
groupRouter.GET("/:id/https", baseApi.GetHTTPSConfig)
groupRouter.POST("/:id/https", baseApi.UpdateHTTPSConfig)
groupRouter.POST("/waf/config", baseApi.GetWebsiteWafConfig)
groupRouter.POST("/waf/update", baseApi.UpdateWebsiteWafConfig)
groupRouter.POST("/waf/file/update", baseApi.UpdateWebsiteWafFile)
groupRouter.GET("/php/config/:id", baseApi.GetWebsitePHPConfig)
groupRouter.POST("/php/config", baseApi.UpdateWebsitePHPConfig)
groupRouter.POST("/php/update", baseApi.UpdatePHPFile)

212
cmd/server/docs/docs.go

@ -1,5 +1,5 @@
// Code generated by swaggo/swag. DO NOT EDIT.
// Package docs GENERATED BY SWAG; DO NOT EDIT
// This file was generated by swaggo/swag
package docs
import "github.com/swaggo/swag"
@ -9158,6 +9158,28 @@ const docTemplate = `{
}
}
},
"/runtimes/sync": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "同步运行环境状态",
"consumes": [
"application/json"
],
"tags": [
"Runtime"
],
"summary": "Sync runtime status",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/runtimes/update": {
"post": {
"security": [
@ -13918,144 +13940,6 @@ const docTemplate = `{
"paramKeys": []
}
}
},
"/websites/waf/config": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取网站 waf 配置",
"consumes": [
"application/json"
],
"tags": [
"Website WAF"
],
"summary": "Load websit waf conf",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.WebsiteWafReq"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.WebsiteWafConfig"
}
}
}
}
},
"/websites/waf/file/update": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "更新 网站 waf 配置文件",
"consumes": [
"application/json"
],
"tags": [
"Website WAF"
],
"summary": "Update website waf file",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.WebsiteWafUpdate"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [
{
"db": "websites",
"input_column": "id",
"input_value": "websiteId",
"isList": false,
"output_column": "primary_domain",
"output_value": "domain"
}
],
"bodyKeys": [
"websiteId"
],
"formatEN": "WAF conf file update [domain]",
"formatZH": "WAF 配置文件修改 [domain]",
"paramKeys": []
}
}
},
"/websites/waf/update": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "更新 网站 waf 配置",
"consumes": [
"application/json"
],
"tags": [
"Website WAF"
],
"summary": "Update website waf conf",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.WebsiteWafUpdate"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [
{
"db": "websites",
"input_column": "id",
"input_value": "websiteId",
"isList": false,
"output_column": "primary_domain",
"output_value": "domain"
}
],
"bodyKeys": [
"websiteId"
],
"formatEN": "WAF conf update [domain]",
"formatZH": "WAF 配置修改 [domain]",
"paramKeys": []
}
}
}
},
"definitions": {
@ -20777,43 +20661,6 @@ const docTemplate = `{
}
}
},
"request.WebsiteWafReq": {
"type": "object",
"required": [
"key",
"rule",
"websiteId"
],
"properties": {
"key": {
"type": "string"
},
"rule": {
"type": "string"
},
"websiteId": {
"type": "integer"
}
}
},
"request.WebsiteWafUpdate": {
"type": "object",
"required": [
"key",
"websiteId"
],
"properties": {
"enable": {
"type": "boolean"
},
"key": {
"type": "string"
},
"websiteId": {
"type": "integer"
}
}
},
"response.AppDTO": {
"type": "object",
"properties": {
@ -21493,17 +21340,6 @@ const docTemplate = `{
"type": "string"
}
}
},
"response.WebsiteWafConfig": {
"type": "object",
"properties": {
"content": {
"type": "string"
},
"enable": {
"type": "boolean"
}
}
}
}
}`

208
cmd/server/docs/swagger.json

@ -9151,6 +9151,28 @@
}
}
},
"/runtimes/sync": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "同步运行环境状态",
"consumes": [
"application/json"
],
"tags": [
"Runtime"
],
"summary": "Sync runtime status",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/runtimes/update": {
"post": {
"security": [
@ -13911,144 +13933,6 @@
"paramKeys": []
}
}
},
"/websites/waf/config": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取网站 waf 配置",
"consumes": [
"application/json"
],
"tags": [
"Website WAF"
],
"summary": "Load websit waf conf",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.WebsiteWafReq"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.WebsiteWafConfig"
}
}
}
}
},
"/websites/waf/file/update": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "更新 网站 waf 配置文件",
"consumes": [
"application/json"
],
"tags": [
"Website WAF"
],
"summary": "Update website waf file",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.WebsiteWafUpdate"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [
{
"db": "websites",
"input_column": "id",
"input_value": "websiteId",
"isList": false,
"output_column": "primary_domain",
"output_value": "domain"
}
],
"bodyKeys": [
"websiteId"
],
"formatEN": "WAF conf file update [domain]",
"formatZH": "WAF 配置文件修改 [domain]",
"paramKeys": []
}
}
},
"/websites/waf/update": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "更新 网站 waf 配置",
"consumes": [
"application/json"
],
"tags": [
"Website WAF"
],
"summary": "Update website waf conf",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.WebsiteWafUpdate"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFunctions": [
{
"db": "websites",
"input_column": "id",
"input_value": "websiteId",
"isList": false,
"output_column": "primary_domain",
"output_value": "domain"
}
],
"bodyKeys": [
"websiteId"
],
"formatEN": "WAF conf update [domain]",
"formatZH": "WAF 配置修改 [domain]",
"paramKeys": []
}
}
}
},
"definitions": {
@ -20770,43 +20654,6 @@
}
}
},
"request.WebsiteWafReq": {
"type": "object",
"required": [
"key",
"rule",
"websiteId"
],
"properties": {
"key": {
"type": "string"
},
"rule": {
"type": "string"
},
"websiteId": {
"type": "integer"
}
}
},
"request.WebsiteWafUpdate": {
"type": "object",
"required": [
"key",
"websiteId"
],
"properties": {
"enable": {
"type": "boolean"
},
"key": {
"type": "string"
},
"websiteId": {
"type": "integer"
}
}
},
"response.AppDTO": {
"type": "object",
"properties": {
@ -21486,17 +21333,6 @@
"type": "string"
}
}
},
"response.WebsiteWafConfig": {
"type": "object",
"properties": {
"content": {
"type": "string"
},
"enable": {
"type": "boolean"
}
}
}
}
}

133
cmd/server/docs/swagger.yaml

@ -4517,31 +4517,6 @@ definitions:
- id
- user
type: object
request.WebsiteWafReq:
properties:
key:
type: string
rule:
type: string
websiteId:
type: integer
required:
- key
- rule
- websiteId
type: object
request.WebsiteWafUpdate:
properties:
enable:
type: boolean
key:
type: string
websiteId:
type: integer
required:
- key
- websiteId
type: object
response.AppDTO:
properties:
createdAt:
@ -4990,13 +4965,6 @@ definitions:
version:
type: string
type: object
response.WebsiteWafConfig:
properties:
content:
type: string
enable:
type: boolean
type: object
host: localhost
info:
contact: {}
@ -10791,6 +10759,19 @@ paths:
summary: List runtimes
tags:
- Runtime
/runtimes/sync:
post:
consumes:
- application/json
description: 同步运行环境状态
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Sync runtime status
tags:
- Runtime
/runtimes/update:
post:
consumes:
@ -13810,92 +13791,4 @@ paths:
formatEN: Update website [primaryDomain]
formatZH: 更新网站 [primaryDomain]
paramKeys: []
/websites/waf/config:
post:
consumes:
- application/json
description: 获取网站 waf 配置
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/request.WebsiteWafReq'
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.WebsiteWafConfig'
security:
- ApiKeyAuth: []
summary: Load websit waf conf
tags:
- Website WAF
/websites/waf/file/update:
post:
consumes:
- application/json
description: 更新 网站 waf 配置文件
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/request.WebsiteWafUpdate'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Update website waf file
tags:
- Website WAF
x-panel-log:
BeforeFunctions:
- db: websites
input_column: id
input_value: websiteId
isList: false
output_column: primary_domain
output_value: domain
bodyKeys:
- websiteId
formatEN: WAF conf file update [domain]
formatZH: WAF 配置文件修改 [domain]
paramKeys: []
/websites/waf/update:
post:
consumes:
- application/json
description: 更新 网站 waf 配置
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/request.WebsiteWafUpdate'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Update website waf conf
tags:
- Website WAF
x-panel-log:
BeforeFunctions:
- db: websites
input_column: id
input_value: websiteId
isList: false
output_column: primary_domain
output_value: domain
bodyKeys:
- websiteId
formatEN: WAF conf update [domain]
formatZH: WAF 配置修改 [domain]
paramKeys: []
swagger: "2.0"

16
cmd/server/nginx_conf/website_default.conf

@ -16,22 +16,6 @@ server {
access_log /www/sites/domain/log/access.log;
error_log /www/sites/domain/log/error.log;
access_by_lua_file /www/common/waf/access.lua;
set $RulePath /www/sites/domain/waf/rules;
set $logdir /www/sites/domain/waf/log;
set $redirect on;
set $attackLog on;
set $CCDeny off;
set $urlWhiteAllow off;
set $urlBlockDeny off;
set $argsDeny off;
set $postDeny off;
set $cookieDeny off;
set $fileExtDeny off;
set $ipBlockDeny off;
set $ipWhiteAllow off;
location ^~ /.well-known/acme-challenge {
allow all;
root /usr/share/nginx/html;

23
frontend/src/api/interface/website.ts

@ -258,29 +258,6 @@ export namespace Website {
appName: string;
}
export interface WafReq {
websiteId: number;
key: string;
rule: string;
}
export interface WafRes {
enable: boolean;
content: string;
}
export interface WafUpdate {
enable: boolean;
websiteId: number;
key: string;
}
export interface WafFileUpdate {
websiteId: number;
type: string;
content: string;
}
export interface DelReq {
id: number;
}

12
frontend/src/api/modules/website.ts

@ -144,18 +144,6 @@ export const PreCheck = (req: Website.CheckReq) => {
return http.post<Website.CheckRes[]>(`/websites/check`, req);
};
export const GetWafConfig = (req: Website.WafReq) => {
return http.post<Website.WafRes>(`/websites/waf/config`, req);
};
export const UpdateWafEnable = (req: Website.WafUpdate) => {
return http.post<any>(`/websites/waf/update`, req);
};
export const UpdateWafFile = (req: Website.WafFileUpdate) => {
return http.post<any>(`/websites/waf/file/update`, req);
};
export const UpdateNginxFile = (req: Website.NginxUpdate) => {
return http.post<any>(`/websites/nginx/update`, req);
};

4
frontend/src/views/website/website/config/index.vue

@ -21,9 +21,6 @@
<el-button type="primary" :plain="index !== 'basic'" @click="changeTab('basic')">
{{ $t('website.basic') }}
</el-button>
<el-button type="primary" :plain="index !== 'safety'" @click="changeTab('safety')">
{{ $t('website.security') }}
</el-button>
<el-button type="primary" :plain="index !== 'log'" @click="changeTab('log')">
{{ $t('website.log') }}
</el-button>
@ -48,7 +45,6 @@
<script setup lang="ts">
import { onMounted, ref, watch } from 'vue';
import Basic from './basic/index.vue';
import Safety from './safety/index.vue';
import Resource from './resource/index.vue';
import Log from './log/index.vue';
import PHP from './php/index.vue';

129
frontend/src/views/website/website/config/safety/ccdeny/index.vue

@ -1,129 +0,0 @@
<template>
<el-row :gutter="20" v-loading="loading">
<el-col :xs="24" :sm="18" :md="10" :lg="10" :xl="10">
<el-form ref="wafForm" label-position="left" label-width="auto" :model="form" :rules="rules">
<el-form-item prop="enable" :label="$t('website.enable')">
<el-switch v-model="form.enable" @change="updateEnable"></el-switch>
</el-form-item>
<el-form-item prop="cycle" :label="$t('website.cycle')">
<el-input v-model.number="form.cycle" maxlength="15">
<template #append>{{ $t('commons.units.second') }}</template>
</el-input>
</el-form-item>
<el-form-item prop="frequency" :label="$t('website.frequency')">
<el-input v-model.number="form.frequency" maxlength="15">
<template #append>{{ $t('commons.units.time') }}</template>
</el-input>
</el-form-item>
<el-alert
:title="$t('website.ccHelper', [form.cycle, form.frequency])"
type="info"
:closable="false"
></el-alert>
<el-form-item></el-form-item>
<el-form-item>
<el-button type="primary" @click="submit(wafForm)">
{{ $t('commons.button.save') }}
</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</template>
<script lang="ts" setup>
import { Website } from '@/api/interface/website';
import { GetWafConfig, UpdateWafEnable, UpdateWafFile } from '@/api/modules/website';
import { checkNumberRange, Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { FormInstance } from 'element-plus';
import { computed, onMounted, reactive, ref } from 'vue';
const props = defineProps({
id: {
type: Number,
default: 0,
},
});
const id = computed(() => {
return props.id;
});
const data = ref<Website.WafRes>();
const loading = ref(false);
const form = reactive({
enable: false,
cycle: 60,
frequency: 120,
});
const req = ref<Website.WafReq>({
websiteId: 0,
key: '$CCDeny',
rule: 'cc',
});
const enableUpdate = ref<Website.WafUpdate>({
websiteId: 0,
key: '$CCDeny',
enable: false,
});
const fileUpdate = reactive({
content: '',
websiteId: 0,
type: 'cc',
});
const rules = ref({
cycle: [Rules.requiredInput, checkNumberRange(1, 9999999)],
frequency: [Rules.requiredInput, checkNumberRange(1, 9999999)],
});
const wafForm = ref<FormInstance>();
const get = async () => {
loading.value = true;
const res = await GetWafConfig(req.value);
loading.value = false;
data.value = res.data;
form.enable = data.value.enable;
if (data.value.content != '') {
const params = data.value.content.split('/');
form.frequency = Number(params[0]);
form.cycle = Number(params[1]);
}
};
const updateEnable = async (enable: boolean) => {
enableUpdate.value.enable = enable;
loading.value = true;
try {
await UpdateWafEnable(enableUpdate.value);
} catch (error) {
form.enable = !enable;
}
loading.value = false;
};
const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate((valid) => {
if (!valid) {
return;
}
fileUpdate.content = String(form.frequency) + '/' + String(form.cycle);
loading.value = true;
UpdateWafFile(fileUpdate)
.then(() => {
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
})
.finally(() => {
loading.value = false;
});
});
};
onMounted(() => {
req.value.websiteId = id.value;
enableUpdate.value.websiteId = id.value;
fileUpdate.websiteId = id.value;
get();
});
</script>

134
frontend/src/views/website/website/config/safety/file-block-list/index.vue

@ -1,134 +0,0 @@
<template>
<el-row>
<el-col :xs="24" :sm="18" :md="10" :lg="10" :xl="10">
<el-form-item prop="enable" :label="$t('website.enable')">
<el-switch v-model="enableUpdate.enable" @change="updateEnable"></el-switch>
</el-form-item>
<el-form-item :label="$t('website.ext')">
<el-input type="textarea" :rows="3" v-model="exts" :placeholder="$t('website.wafInputHelper')" />
</el-form-item>
<ComplexTable :data="data" v-loading="loading">
<template #toolbar>
<el-button type="primary" icon="Plus" @click="openCreate">
{{ $t('commons.button.add') }}
</el-button>
</template>
<el-table-column :label="$t('website.fileExt')" prop="file"></el-table-column>
<el-table-column :label="$t('commons.table.operate')">
<template #default="{ $index }">
<el-button link type="primary" @click="remove($index)">
{{ $t('commons.button.delete') }}
</el-button>
</template>
</el-table-column>
</ComplexTable>
</el-col>
</el-row>
</template>
<script lang="ts" setup>
import { Website } from '@/api/interface/website';
import { GetWafConfig, UpdateWafEnable, UpdateWafFile } from '@/api/modules/website';
import { computed, onMounted, reactive, ref } from 'vue';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
const props = defineProps({
id: {
type: Number,
default: 0,
},
});
const id = computed(() => {
return props.id;
});
const loading = ref(false);
const data = ref([]);
const req = ref<Website.WafReq>({
websiteId: 0,
key: '$fileExtDeny',
rule: 'file_ext_block',
});
const fileUpdate = reactive({
content: '',
websiteId: 0,
type: 'file_ext_block',
});
const enableUpdate = ref<Website.WafUpdate>({
websiteId: 0,
key: '$fileExtDeny',
enable: false,
});
const exts = ref();
const get = async () => {
data.value = [];
loading.value = true;
const res = await GetWafConfig(req.value);
loading.value = false;
if (res.data.content != '') {
const ipList = JSON.parse(res.data.content);
ipList.forEach((value: string) => {
data.value.push({
file: value,
});
});
}
enableUpdate.value.enable = res.data.enable;
};
const remove = (index: number) => {
const copyList = data.value.concat();
copyList.splice(index, 1);
const extArray = [];
copyList.forEach((d) => {
extArray.push(d.file);
});
submit(extArray);
};
const openCreate = () => {
const extArray = exts.value.split('\n');
if (extArray.length === 0) {
return;
}
data.value.forEach((d) => {
extArray.push(d.file);
});
submit(extArray);
};
const submit = async (extArray: string[]) => {
fileUpdate.content = JSON.stringify(extArray);
loading.value = true;
UpdateWafFile(fileUpdate)
.then(() => {
exts.value = '';
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
get();
})
.finally(() => {
loading.value = false;
});
};
const updateEnable = async (enable: boolean) => {
enableUpdate.value.enable = enable;
loading.value = true;
try {
await UpdateWafEnable(enableUpdate.value);
} catch (error) {
enableUpdate.value.enable = !enable;
}
loading.value = false;
};
onMounted(() => {
req.value.websiteId = id.value;
enableUpdate.value.websiteId = id.value;
fileUpdate.websiteId = id.value;
get();
});
</script>

74
frontend/src/views/website/website/config/safety/index.vue

@ -1,74 +0,0 @@
<template>
<el-tabs tab-position="left" v-model="index">
<el-tab-pane :label="$t('firewall.ccDeny')" name="cc">
<CCDeny :id="id" v-if="index == 'cc'"></CCDeny>
</el-tab-pane>
<el-tab-pane :label="$t('firewall.ipWhiteList')" name="ipWhiteList">
<SimpleList
:id="id"
:rule="'ip_white'"
:param-key="'$ipWhiteAllow'"
v-if="index == 'ipWhiteList'"
></SimpleList>
</el-tab-pane>
<el-tab-pane :label="$t('firewall.ipBlockList')" name="ipBlockList">
<SimpleList
:id="id"
:rule="'ip_block'"
:param-key="'$ipBlockDeny'"
v-if="index == 'ipBlockList'"
></SimpleList>
</el-tab-pane>
<el-tab-pane :label="$t('firewall.urlWhiteList')" name="urlWhiteList">
<SimpleList
:id="id"
:rule="'url_white'"
:param-key="'$urlWhiteAllow'"
v-if="index == 'urlWhiteList'"
></SimpleList>
</el-tab-pane>
<el-tab-pane :label="$t('firewall.urlBlockList')" name="urlBlockList">
<SimpleList
:id="id"
:rule="'url_block'"
:param-key="'$urlBlockDeny'"
v-if="index == 'urlBlockList'"
></SimpleList>
</el-tab-pane>
<el-tab-pane :label="$t('firewall.cookieBlockList')" name="cookie">
<ValueList :id="id" :rule="'cookie_block'" :param-key="'$cookieDeny'" v-if="index == 'cookie'"></ValueList>
</el-tab-pane>
<el-tab-pane :label="$t('firewall.argsCheck')" name="args">
<ValueList :id="id" :rule="'args_check'" :param-key="'$argsDeny'" v-if="index == 'args'"></ValueList>
</el-tab-pane>
<el-tab-pane :label="$t('firewall.postCheck')" name="post">
<ValueList :id="id" :rule="'post_check'" :param-key="'$postDeny'" v-if="index == 'post'"></ValueList>
</el-tab-pane>
<el-tab-pane :label="$t('firewall.userAgent')" name="ua">
<ValueList :id="id" :rule="'user_agent'" :param-key="'$userAgent'" v-if="index == 'ua'"></ValueList>
</el-tab-pane>
<el-tab-pane :label="$t('firewall.fileExtBlockList')" name="fileExtBlockList">
<FileBlockList :id="id" v-if="index == 'fileExtBlockList'"></FileBlockList>
</el-tab-pane>
</el-tabs>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue';
import CCDeny from './ccdeny/index.vue';
import SimpleList from './simple-list/index.vue';
import FileBlockList from './file-block-list/index.vue';
import ValueList from './value-list/index.vue';
const props = defineProps({
id: {
type: Number,
default: 0,
},
});
const id = computed(() => {
return props.id;
});
let index = ref('cc');
</script>

181
frontend/src/views/website/website/config/safety/simple-list/index.vue

@ -1,181 +0,0 @@
<template>
<el-row>
<el-col :xs="24" :sm="18" :md="10" :lg="10" :xl="10">
<el-form-item prop="enable" :label="$t('website.enable')">
<el-switch v-model="enableUpdate.enable" @change="updateEnable"></el-switch>
</el-form-item>
<el-form-item>
<el-alert
type="info"
v-if="rule === 'ip_white'"
:title="$t('website.ipWhiteListHelper')"
:closable="false"
/>
</el-form-item>
<el-form-item :label="$t('website.ipValue')">
<el-input type="textarea" :rows="3" v-model="ips" :placeholder="$t('website.wafInputHelper')" />
</el-form-item>
<ComplexTable :data="data" v-loading="loading">
<template #toolbar>
<el-button type="primary" icon="Plus" @click="openCreate">
{{ $t('commons.button.add') }}
</el-button>
</template>
<el-table-column :label="$t('website.ipValue')" prop="ip"></el-table-column>
<el-table-column :label="$t('commons.table.operate')">
<template #default="{ $index }">
<el-button link type="primary" @click="removeIp($index)">
{{ $t('commons.button.delete') }}
</el-button>
</template>
</el-table-column>
</ComplexTable>
</el-col>
</el-row>
</template>
<script lang="ts" setup>
import { Website } from '@/api/interface/website';
import { GetWafConfig, UpdateWafEnable, UpdateWafFile } from '@/api/modules/website';
import { computed, onMounted, reactive, ref } from 'vue';
import i18n from '@/lang';
import { checkIpV4V6 } from '@/utils/util';
import { MsgSuccess } from '@/utils/message';
import { MsgError } from '@/utils/message';
const props = defineProps({
id: {
type: Number,
default: 0,
},
rule: {
type: String,
default: 'ip_white',
},
paramKey: {
type: String,
default: '$ipWhiteAllow',
},
});
const id = computed(() => {
return props.id;
});
const rule = computed(() => {
return props.rule;
});
const key = computed(() => {
return props.paramKey;
});
const loading = ref(false);
const data = ref([]);
const req = ref<Website.WafReq>({
websiteId: 0,
key: '$ipWhiteAllow',
rule: 'ip_white',
});
const fileUpdate = reactive({
content: '',
websiteId: 0,
type: 'ip_white',
});
const enableUpdate = ref<Website.WafUpdate>({
websiteId: 0,
key: '$ipWhiteAllow',
enable: false,
});
const ips = ref();
const get = async () => {
data.value = [];
loading.value = true;
const res = await GetWafConfig(req.value);
loading.value = false;
if (res.data.content != '') {
const ipList = JSON.parse(res.data.content);
ipList.forEach((ip: string) => {
data.value.push({
ip: ip,
});
});
}
enableUpdate.value.enable = res.data.enable;
};
const removeIp = (index: number) => {
const copyList = data.value.concat();
copyList.splice(index, 1);
let ipArray = [];
copyList.forEach((d) => {
ipArray.push(d.ip);
});
submit(ipArray);
};
const openCreate = () => {
const ipArray = ips.value.split('\n');
if (ipArray.length == 0) {
return;
}
let newIpArray = [];
ipArray.forEach((ip: string) => {
const newIp = ip.replace(/(^\s*)|(\s*$)/g, '');
if (newIp != '') {
newIpArray.push(newIp);
}
});
if (newIpArray.length == 0) {
return;
}
if (req.value.rule.indexOf('ip') > -1) {
for (const id in newIpArray) {
if (checkIpV4V6(newIpArray[id])) {
MsgError(i18n.global.t('commons.rule.ipErr', [ipArray[id]]));
return;
}
}
}
data.value.forEach((d) => {
newIpArray.push(d.ip);
});
if (newIpArray.length > 0) {
submit(newIpArray);
}
};
const submit = async (ipList: string[]) => {
fileUpdate.content = JSON.stringify(ipList);
loading.value = true;
UpdateWafFile(fileUpdate)
.then(() => {
ips.value = '';
get();
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
})
.finally(() => {
loading.value = false;
});
};
const updateEnable = async (enable: boolean) => {
enableUpdate.value.enable = enable;
loading.value = true;
try {
await UpdateWafEnable(enableUpdate.value);
} catch (error) {
enableUpdate.value.enable = !enable;
}
loading.value = false;
};
onMounted(() => {
req.value.websiteId = id.value;
req.value.rule = rule.value;
req.value.key = key.value;
enableUpdate.value.websiteId = id.value;
enableUpdate.value.key = key.value;
fileUpdate.type = rule.value;
fileUpdate.websiteId = id.value;
get();
});
</script>

184
frontend/src/views/website/website/config/safety/value-list/index.vue

@ -1,184 +0,0 @@
<template>
<el-row>
<el-col :xs="24" :sm="18" :md="14" :lg="14" :xl="14">
<el-form>
<el-form-item prop="enable" :label="$t('website.enable')" v-if="rule != 'user_agent'">
<el-switch v-model="enableUpdate.enable" @change="updateEnable"></el-switch>
</el-form-item>
<el-form-item :label="$t('website.data')">
<el-row :gutter="10" style="width: 100%">
<el-col :span="12">
<el-input
type="text"
v-model="add.value"
label="value"
:placeholder="$t('website.wafValueHelper')"
/>
</el-col>
<el-col :span="12">
<el-input
type="text"
v-model="add.remark"
label="remark"
:placeholder="$t('website.wafRemarkHelper')"
/>
</el-col>
</el-row>
</el-form-item>
</el-form>
<ComplexTable :data="data" v-loading="loading">
<template #toolbar>
<el-button type="primary" icon="Plus" @click="openCreate">
{{ $t('commons.button.add') }}
</el-button>
</template>
<el-table-column :label="$t('website.value')" prop="value"></el-table-column>
<el-table-column :label="$t('website.remark')" prop="remark"></el-table-column>
<el-table-column :label="$t('commons.table.operate')" width="100px">
<template #default="{ $index }">
<el-button link type="primary" @click="remove($index)">
{{ $t('commons.button.delete') }}
</el-button>
</template>
</el-table-column>
</ComplexTable>
</el-col>
</el-row>
</template>
<script lang="ts" setup>
import { Website } from '@/api/interface/website';
import { GetWafConfig, UpdateWafEnable, UpdateWafFile } from '@/api/modules/website';
import { computed, onMounted, reactive, ref } from 'vue';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
const props = defineProps({
id: {
type: Number,
default: 0,
},
rule: {
type: String,
default: 'url',
},
paramKey: {
type: String,
default: 'url',
},
});
const id = computed(() => {
return props.id;
});
const rule = computed(() => {
return props.rule;
});
const key = computed(() => {
return props.paramKey;
});
const loading = ref(false);
const data = ref([]);
const req = ref<Website.WafReq>({
websiteId: 0,
key: '',
rule: 'url',
});
const fileUpdate = reactive({
content: '',
websiteId: 0,
type: 'url',
});
const enableUpdate = ref<Website.WafUpdate>({
websiteId: 0,
key: '$UrlDeny',
enable: false,
});
let add = ref({
value: '',
remark: '',
enable: 1,
});
let contentArray = ref([]);
const get = async () => {
data.value = [];
loading.value = true;
const res = await GetWafConfig(req.value);
loading.value = false;
enableUpdate.value.enable = res.data.enable;
if (res.data.content != '') {
contentArray.value = JSON.parse(res.data.content);
contentArray.value.forEach((value) => {
if (value != '') {
data.value.push({
value: value[0],
remark: value[1],
enable: value[2],
});
}
});
}
};
const remove = (index: number) => {
contentArray.value.splice(index, 1);
submit([]);
};
const openCreate = () => {
if (add.value.value == '') {
return;
}
let newArray = [];
newArray[0] = add.value.value;
newArray[1] = add.value.remark;
newArray[2] = add.value.enable;
data.value.push(newArray);
submit(newArray);
};
const updateEnable = async (enable: boolean) => {
enableUpdate.value.enable = enable;
loading.value = true;
try {
await UpdateWafEnable(enableUpdate.value);
} catch (error) {
enableUpdate.value.enable = !enable;
}
loading.value = false;
};
const submit = async (addArray: string[]) => {
if (addArray.length > 0) {
contentArray.value.push(addArray);
}
fileUpdate.content = JSON.stringify(contentArray.value);
loading.value = true;
UpdateWafFile(fileUpdate)
.then(() => {
add.value = {
value: '',
remark: '',
enable: 1,
};
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
get();
})
.finally(() => {
loading.value = false;
});
};
onMounted(() => {
req.value.websiteId = id.value;
req.value.rule = rule.value;
req.value.key = key.value;
enableUpdate.value.key = key.value;
enableUpdate.value.websiteId = id.value;
fileUpdate.websiteId = id.value;
fileUpdate.type = rule.value;
get();
});
</script>

10
frontend/src/views/website/website/index.vue

@ -281,10 +281,6 @@ const openConfig = (id: number) => {
router.push({ name: 'WebsiteConfig', params: { id: id, tab: 'basic' } });
};
const openWAF = (id: number) => {
router.push({ name: 'WebsiteConfig', params: { id: id, tab: 'safety' } });
};
const isEver = (time: string) => {
const expireDate = new Date(time);
return expireDate < new Date('1970-01-02');
@ -356,12 +352,6 @@ const buttons = [
openConfig(row.id);
},
},
{
label: 'WAF',
click: function (row: Website.Website) {
openWAF(row.id);
},
},
{
label: i18n.global.t('database.backupList'),
click: (row: Website.Website) => {

Loading…
Cancel
Save