Compare commits

...

56 Commits

Author SHA1 Message Date
刘祥超
5e62769dcf 修改版本为0.6.2 2023-01-10 21:17:20 +08:00
刘祥超
86b8a718a0 在Dockerfile中增加local repository提示 2023-01-10 18:31:28 +08:00
刘祥超
a729cfc31d 更新Dockerfile文件 2023-01-10 10:53:48 +08:00
刘祥超
96cfda852a Dockerfile版本号更新到0.6.0 2023-01-09 20:45:04 +08:00
刘祥超
0423d9246c 更新components.js 2023-01-09 18:12:45 +08:00
刘祥超
985798757f 修复<values-box>组件内容中如果出现数字的显示问题 2023-01-09 18:08:24 +08:00
刘祥超
72876f6749 版本修改为0.6.1 2023-01-09 16:06:13 +08:00
刘祥超
03d6e223d8 更新components.js 2023-01-09 09:31:19 +08:00
刘祥超
62d9f2ed97 优化文字提示 2023-01-08 19:38:50 +08:00
刘祥超
a550a44a52 集群服务设置增加自动读超时选项 2023-01-07 20:04:42 +08:00
刘祥超
b19d586949 更新components.js 2023-01-07 19:34:48 +08:00
刘祥超
bbfa3ee57f 优化任务Badge检查频率 2023-01-07 19:34:40 +08:00
刘祥超
af409dd3b8 优化WAF规则显示样式 2023-01-06 20:06:30 +08:00
刘祥超
3db79ca149 更新components.js 2023-01-06 19:17:31 +08:00
刘祥超
e880420494 WAF规则使用中文显示运算符 2023-01-06 19:12:53 +08:00
刘祥超
28ec17b8fe 优化请求条件操作符描述 2023-01-06 16:05:06 +08:00
刘祥超
8026a40807 修改一处错别字 2023-01-05 10:27:59 +08:00
刘祥超
068c6d406a useragent改为userAgent 2023-01-02 18:20:42 +08:00
刘祥超
57470e4ef0 集群服务设置中增加性能设置 2023-01-01 19:26:59 +08:00
刘祥超
ca8e1537f5 修复文字错误 2023-01-01 18:33:05 +08:00
刘祥超
d67b818398 华为云可以设置终端节点(endpoint) 2023-01-01 18:28:37 +08:00
刘祥超
f5f46424bb 集群/节点阈值切换监控项时同时切换参数描述 2022-12-31 18:33:42 +08:00
刘祥超
1e259717ce 优化代码 2022-12-31 17:31:17 +08:00
刘祥超
91ece99a9c 优化证书加载速度 2022-12-31 17:21:48 +08:00
刘祥超
d30ebdb369 优化证书数量很多时的页面加载速度 2022-12-31 17:12:49 +08:00
刘祥超
ade8522b69 实现UA名单功能 2022-12-30 20:48:38 +08:00
刘祥超
159b308f31 内容压缩增加默认内容长度限制 2022-12-30 14:37:50 +08:00
刘祥超
837bf25f7b 内容压缩支持例外扩展名 2022-12-30 12:04:17 +08:00
刘祥超
8301d3669b 默认情况下内容压缩不支持Partial Content 2022-12-30 11:43:47 +08:00
刘祥超
cc752e8d80 优化文字提示 2022-12-29 17:19:53 +08:00
刘祥超
d20e6bd42f 增加CORS自适应跨域 2022-12-29 17:16:07 +08:00
刘祥超
bfee9fe233 优化文字提示 2022-12-27 18:55:18 +08:00
刘祥超
9c962b09f1 调整文字提示 2022-12-22 11:43:31 +08:00
刘祥超
46edefead7 服务没有设置所属用户时可以设置一个用户 2022-12-21 16:13:39 +08:00
刘祥超
725cfc8a2b 优化代码 2022-12-15 16:18:10 +08:00
刘祥超
1ce48b9ef4 安全设置中检查搜索引擎和爬虫时不区分大小写 2022-12-13 18:22:11 +08:00
刘祥超
37cc28f225 优化界面 2022-12-13 18:21:31 +08:00
刘祥超
5ebe3bb8e0 实时访问日志有弹窗打开时,暂时不更新数据 2022-12-10 19:01:57 +08:00
刘祥超
aa01512f89 优化<more-options-indicator>组件 2022-12-10 15:57:39 +08:00
刘祥超
37ff2b886a 初步完成用户电子邮箱绑定(激活) 2022-12-08 20:25:20 +08:00
刘祥超
ce18212756 自定义线路增加区域之间关系设置 2022-12-06 22:32:32 +08:00
刘祥超
08f50a274a 修复HTTPS之HSTS设置无法手动输入有效时间的Bug 2022-12-06 14:38:59 +08:00
刘祥超
892ee0013a 修复点击修改WAF规则时未保存时也会生效的Bug 2022-12-06 10:46:46 +08:00
刘祥超
e9a47041fd 刷新预热页面增加功能说明 2022-12-06 09:52:57 +08:00
刘祥超
d419fa06e8 优化文字提示 2022-12-03 14:29:30 +08:00
刘祥超
8b961a890c 优化文字提示 2022-12-01 14:40:17 +08:00
刘祥超
db32915114 更新components.js 2022-11-29 15:40:37 +08:00
刘祥超
2ffdb10cce 版本号更新为0.6.0 2022-11-29 15:40:23 +08:00
刘祥超
507fd7e5d4 更新Dockerfile中的版本号 2022-11-29 15:40:11 +08:00
刘祥超
7df599b5a9 DNS线路选择器增加代号搜索 2022-11-28 19:00:14 +08:00
刘祥超
9987334f55 版本号修改为0.5.10 2022-11-28 18:59:40 +08:00
刘祥超
d8c3365384 节点时间相差30秒钟以上才提示 2022-11-28 15:57:41 +08:00
刘祥超
2e284b5af9 版本号修改为0.5.9 2022-11-28 15:57:18 +08:00
刘祥超
89ddd4e6a3 更新依赖库 2022-11-28 11:39:38 +08:00
刘祥超
36524ea481 修复一处测试用例package引用错误 2022-11-28 11:39:08 +08:00
刘祥超
35cf693610 更新Dockerfile 2022-11-28 11:34:02 +08:00
99 changed files with 2078 additions and 453 deletions

View File

@@ -1,10 +1,11 @@
FROM alpine:latest
LABEL maintainer="iwind.liu@gmail.com"
ENV TZ "Asia/Shanghai"
ENV VERSION 0.5.7
ENV VERSION 0.6.1
ENV ROOT_DIR /usr/local/goedge
ENV TAR_FILE edge-admin-linux-amd64-plus-v${VERSION}.zip
ENV TAR_URL "https://dl.goedge.cn/edge/v${VERSION}/edge-admin-linux-amd64-plus-v${VERSION}.zip"
#ENV TAR_URL "http://192.168.2.60:8080/edge-admin-linux-amd64-plus-v${VERSION}.zip" # your local repository
RUN apk add --no-cache tzdata

8
go.mod
View File

@@ -15,9 +15,9 @@ require (
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/tealeg/xlsx/v3 v3.2.3
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad
golang.org/x/sys v0.2.0
google.golang.org/grpc v1.45.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
gopkg.in/yaml.v3 v3.0.1
)
require (
@@ -36,8 +36,8 @@ require (
github.com/rogpeppe/fastuuid v1.2.0 // indirect
github.com/shabbyrobe/xmlwriter v0.0.0-20200208144257-9fca06d00ffa // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/net v0.2.0 // indirect
golang.org/x/text v0.4.0 // indirect
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect

20
go.sum
View File

@@ -74,6 +74,7 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iwind/TeaGo v0.0.0-20210411134150-ddf57e240c2f/go.mod h1:KU4mS7QNiZ7QWEuDBk1zw0/Q2LrAPZv3tycEFBsuUwc=
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475 h1:EseyfFaQOjWanGiby9KMw7PjDBMg/95tLDgIw/ns0Cw=
github.com/iwind/TeaGo v0.0.0-20220304043459-0dd944a5b475/go.mod h1:HRHK0zoC/og3c9/hKosD9yYVMTnnzm3PgXUdhRYHaLc=
github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4 h1:VWGsCqTzObdlbf7UUE3oceIpcEKi4C/YBUszQXk118A=
@@ -170,8 +171,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -198,20 +199,16 @@ golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -266,7 +263,8 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -1,9 +1,9 @@
package teaconst
const (
Version = "0.5.8"
Version = "0.6.2"
APINodeVersion = "0.5.8"
APINodeVersion = "0.6.2"
ProductName = "Edge Admin"
ProcessName = "edge-admin"

View File

@@ -9,6 +9,7 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/conds/condutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/files"
@@ -115,6 +116,16 @@ func generateComponentsJSFile() error {
buffer.Write([]byte{'\n', '\n'})
}
// WAF操作符
wafOperatorsJSON, err := json.Marshal(firewallconfigs.AllRuleOperators)
if err != nil {
logs.Println("ComponentsAction marshal waf rule operators failed: " + err.Error())
} else {
buffer.WriteString("window.WAF_RULE_OPERATORS = ")
buffer.Write(wafOperatorsJSON)
buffer.Write([]byte{'\n', '\n'})
}
fp, err := os.OpenFile(filepath.Clean(Tea.PublicFile("/js/components.src.js")), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0777)
if err != nil {
return err

View File

@@ -3,7 +3,7 @@
package utils_test
import (
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
"github.com/iwind/TeaGo/assert"
"testing"
)

View File

@@ -85,6 +85,10 @@ func (this *IndexAction) RunPost(params struct {
LogRecordServerError bool
PerformanceAutoReadTimeout bool
PerformanceAutoWriteTimeout bool
PerformanceDebug bool
Must *actions.Must
CSRF *actionutils.CSRF
}) {
@@ -124,17 +128,25 @@ func (this *IndexAction) RunPost(params struct {
}
}
// 域名
config.HTTPAll.AllowMismatchDomains = allowMismatchDomains
config.HTTPAll.AllowNodeIP = params.HttpAllAllowNodeIP
config.HTTPAll.DefaultDomain = params.HttpAllDefaultDomain
// 访问日志
config.HTTPAccessLog.EnableRequestHeaders = params.HttpAccessLogEnableRequestHeaders
config.HTTPAccessLog.EnableResponseHeaders = params.HttpAccessLogEnableResponseHeaders
config.HTTPAccessLog.CommonRequestHeadersOnly = params.HttpAccessLogCommonRequestHeadersOnly
config.HTTPAccessLog.EnableCookies = params.HttpAccessLogEnableCookies
// 日志
config.Log.RecordServerError = params.LogRecordServerError
// 性能
config.Performance.AutoReadTimeout = params.PerformanceAutoReadTimeout
config.Performance.AutoWriteTimeout = params.PerformanceAutoWriteTimeout
config.Performance.Debug = params.PerformanceDebug
err = config.Init()
if err != nil {
this.Fail("配置校验失败:" + err.Error())

View File

@@ -89,6 +89,19 @@ func (this *IndexAction) RunGet(params struct {
}
}
// DNS信息
var fullDomainName = ""
if len(cluster.DnsName) > 0 && cluster.DnsDomainId > 0 {
domainResp, err := this.RPC().DNSDomainRPC().FindBasicDNSDomain(this.AdminContext(), &pb.FindBasicDNSDomainRequest{DnsDomainId: cluster.DnsDomainId})
if err != nil {
this.ErrorPage(err)
return
}
if domainResp.DnsDomain != nil {
fullDomainName = cluster.DnsName + "." + domainResp.DnsDomain.Name
}
}
this.Data["cluster"] = maps.Map{
"id": cluster.Id,
"name": cluster.Name,
@@ -100,6 +113,7 @@ func (this *IndexAction) RunGet(params struct {
"autoRemoteStart": cluster.AutoRemoteStart,
"autoInstallNftables": cluster.AutoInstallNftables,
"sshParams": sshParams,
"domainName": fullDomainName,
}
// 默认值

View File

@@ -3,23 +3,38 @@ package tasks
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"time"
)
type CheckAction struct {
actionutils.ParentAction
}
func (this *CheckAction) RunPost(params struct{}) {
resp, err := this.RPC().NodeTaskRPC().ExistsNodeTasks(this.AdminContext(), &pb.ExistsNodeTasksRequest{
ExcludeTypes: []string{"ipItemChanged"},
})
if err != nil {
this.ErrorPage(err)
return
}
func (this *CheckAction) RunPost(params struct {
IsDoing bool
HasError bool
IsUpdated bool
}) {
var maxTries = 10
for i := 0; i < maxTries; i++ {
resp, err := this.RPC().NodeTaskRPC().ExistsNodeTasks(this.AdminContext(), &pb.ExistsNodeTasksRequest{
ExcludeTypes: []string{"ipItemChanged"},
})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["isDoing"] = resp.ExistTasks
this.Data["hasError"] = resp.ExistError
// 如果没有数据变化,继续查询
if i < maxTries-1 && params.IsUpdated && resp.ExistTasks == params.IsDoing && resp.ExistError == params.HasError {
time.Sleep(3 * time.Second)
continue
}
this.Data["isDoing"] = resp.ExistTasks
this.Data["hasError"] = resp.ExistError
break
}
this.Success()
}

View File

@@ -133,6 +133,11 @@ func ValidateRecordValue(recordType dnsconfigs.RecordType, value string) (messag
message = "请输入正确的邮件服务器域名"
return
}
case dnsconfigs.RecordTypeSRV:
if len(value) == 0 {
message = "请输入主机名"
return
}
case dnsconfigs.RecordTypeTXT:
if len(value) > 512 {
message = "文本长度不能超出512字节"

View File

@@ -64,6 +64,7 @@ func (this *CreatePopupAction) RunPost(params struct {
// HuaweiDNS
ParamHuaweiAccessKeyId string
ParamHuaweiAccessKeySecret string
ParamHuaweiEndpoint string
// CloudFlare
ParamCloudFlareAPIKey string
@@ -119,6 +120,7 @@ func (this *CreatePopupAction) RunPost(params struct {
apiParams["accessKeyId"] = params.ParamHuaweiAccessKeyId
apiParams["accessKeySecret"] = params.ParamHuaweiAccessKeySecret
apiParams["endpoint"] = params.ParamHuaweiEndpoint
case "cloudFlare":
params.Must.
Field("paramCloudFlareAPIKey", params.ParamCloudFlareAPIKey).

View File

@@ -91,6 +91,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
// HuaweiDNS
ParamHuaweiAccessKeyId string
ParamHuaweiAccessKeySecret string
ParamHuaweiEndpoint string
// CloudFlare
ParamCloudFlareAPIKey string
@@ -148,6 +149,7 @@ func (this *UpdatePopupAction) RunPost(params struct {
apiParams["accessKeyId"] = params.ParamHuaweiAccessKeyId
apiParams["accessKeySecret"] = params.ParamHuaweiAccessKeySecret
apiParams["endpoint"] = params.ParamHuaweiEndpoint
case "cloudFlare":
params.Must.
Field("paramCloudFlareAPIKey", params.ParamCloudFlareAPIKey).

View File

@@ -3,21 +3,36 @@ package tasks
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"time"
)
type CheckAction struct {
actionutils.ParentAction
}
func (this *CheckAction) RunPost(params struct{}) {
resp, err := this.RPC().DNSTaskRPC().ExistsDNSTasks(this.AdminContext(), &pb.ExistsDNSTasksRequest{})
if err != nil {
this.ErrorPage(err)
return
}
func (this *CheckAction) RunPost(params struct {
IsDoing bool
HasError bool
IsUpdated bool
}) {
var maxTries = 10
for i := 0; i < maxTries; i++ {
resp, err := this.RPC().DNSTaskRPC().ExistsDNSTasks(this.AdminContext(), &pb.ExistsDNSTasksRequest{})
if err != nil {
this.ErrorPage(err)
return
}
this.Data["isDoing"] = resp.ExistTasks
this.Data["hasError"] = resp.ExistError
// 如果没有数据变化,继续查询
if i < maxTries-1 && params.IsUpdated && resp.ExistTasks == params.IsDoing && resp.ExistError == params.HasError {
time.Sleep(3 * time.Second)
continue
}
this.Data["isDoing"] = resp.ExistTasks
this.Data["hasError"] = resp.ExistError
break
}
this.Success()
}

View File

@@ -55,10 +55,11 @@ func (this *IndexAction) RunGet(params struct {
// 服务列表
serversResp, err := this.RPC().ServerRPC().ListEnabledServersMatch(this.AdminContext(), &pb.ListEnabledServersMatchRequest{
Offset: page.Offset,
Size: page.Size,
ServerGroupId: params.GroupId,
Keyword: params.Keyword,
Offset: page.Offset,
Size: page.Size,
ServerGroupId: params.GroupId,
Keyword: params.Keyword,
IgnoreSSLCerts: true,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -43,7 +43,7 @@ func (this *IndexAction) RunGet(params struct {
this.ErrorPage(err)
return
}
headerPolicyId := createHeaderPolicyResp.HeaderPolicyId
headerPolicyId := createHeaderPolicyResp.HttpHeaderPolicyId
ref := &shared.HTTPHeaderPolicyRef{
IsPrior: false,
IsOn: true,
@@ -70,7 +70,7 @@ func (this *IndexAction) RunGet(params struct {
this.ErrorPage(err)
return
}
headerPolicyId := createHeaderPolicyResp.HeaderPolicyId
headerPolicyId := createHeaderPolicyResp.HttpHeaderPolicyId
ref := &shared.HTTPHeaderPolicyRef{
IsPrior: false,
IsOn: true,

View File

@@ -99,6 +99,7 @@ func (this *IndexAction) RunGet(params struct {
TrafficOutAsc: params.TrafficOutOrder == "asc",
UserId: params.UserId,
IgnoreServerNames: true,
IgnoreSSLCerts: true,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -48,7 +48,10 @@ func (this *UpdateCNAMEPopupAction) RunPost(params struct {
this.FailField("dnsName", "CNAME中只能包含数字、英文字母")
}
serverResp, err := this.RPC().ServerRPC().FindEnabledServer(this.AdminContext(), &pb.FindEnabledServerRequest{ServerId: params.ServerId})
serverResp, err := this.RPC().ServerRPC().FindEnabledServer(this.AdminContext(), &pb.FindEnabledServerRequest{
ServerId: params.ServerId,
IgnoreSSLCerts: true,
})
if err != nil {
this.ErrorPage(err)
return

View File

@@ -40,13 +40,13 @@ func (this *CreateDeletePopupAction) RunPost(params struct {
Field("name", params.Name).
Require("名称不能为空")
policyConfigResp, err := this.RPC().HTTPHeaderPolicyRPC().FindEnabledHTTPHeaderPolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPHeaderPolicyConfigRequest{HeaderPolicyId: params.HeaderPolicyId})
policyConfigResp, err := this.RPC().HTTPHeaderPolicyRPC().FindEnabledHTTPHeaderPolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPHeaderPolicyConfigRequest{HttpHeaderPolicyId: params.HeaderPolicyId})
if err != nil {
this.ErrorPage(err)
return
}
policyConfig := &shared.HTTPHeaderPolicy{}
err = json.Unmarshal(policyConfigResp.HeaderPolicyJSON, policyConfig)
err = json.Unmarshal(policyConfigResp.HttpHeaderPolicyJSON, policyConfig)
if err != nil {
this.ErrorPage(err)
return
@@ -55,8 +55,8 @@ func (this *CreateDeletePopupAction) RunPost(params struct {
deleteHeaders := policyConfig.DeleteHeaders
deleteHeaders = append(deleteHeaders, params.Name)
_, err = this.RPC().HTTPHeaderPolicyRPC().UpdateHTTPHeaderPolicyDeletingHeaders(this.AdminContext(), &pb.UpdateHTTPHeaderPolicyDeletingHeadersRequest{
HeaderPolicyId: params.HeaderPolicyId,
HeaderNames: deleteHeaders,
HttpHeaderPolicyId: params.HeaderPolicyId,
HeaderNames: deleteHeaders,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -52,13 +52,13 @@ func (this *CreateSetPopupAction) RunPost(params struct {
Field("name", params.Name).
Require("请输入Header名称")
configResp, err := this.RPC().HTTPHeaderPolicyRPC().FindEnabledHTTPHeaderPolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPHeaderPolicyConfigRequest{HeaderPolicyId: params.HeaderPolicyId})
configResp, err := this.RPC().HTTPHeaderPolicyRPC().FindEnabledHTTPHeaderPolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPHeaderPolicyConfigRequest{HttpHeaderPolicyId: params.HeaderPolicyId})
if err != nil {
this.ErrorPage(err)
return
}
policyConfig := &shared.HTTPHeaderPolicy{}
err = json.Unmarshal(configResp.HeaderPolicyJSON, policyConfig)
err = json.Unmarshal(configResp.HttpHeaderPolicyJSON, policyConfig)
if err != nil {
this.ErrorPage(err)
return
@@ -135,8 +135,8 @@ func (this *CreateSetPopupAction) RunPost(params struct {
}
_, err = this.RPC().HTTPHeaderPolicyRPC().UpdateHTTPHeaderPolicySettingHeaders(this.AdminContext(), &pb.UpdateHTTPHeaderPolicySettingHeadersRequest{
HeaderPolicyId: params.HeaderPolicyId,
HeadersJSON: refsJSON,
HttpHeaderPolicyId: params.HeaderPolicyId,
HeadersJSON: refsJSON,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -21,14 +21,14 @@ func (this *DeleteAction) RunPost(params struct {
defer this.CreateLog(oplogs.LevelInfo, "删除请求HeaderHeaderPolicyId:%d, HeaderId:%d", params.HeaderPolicyId, params.HeaderId)
policyConfigResp, err := this.RPC().HTTPHeaderPolicyRPC().FindEnabledHTTPHeaderPolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPHeaderPolicyConfigRequest{
HeaderPolicyId: params.HeaderPolicyId,
HttpHeaderPolicyId: params.HeaderPolicyId,
})
if err != nil {
this.ErrorPage(err)
return
}
policyConfig := &shared.HTTPHeaderPolicy{}
err = json.Unmarshal(policyConfigResp.HeaderPolicyJSON, policyConfig)
err = json.Unmarshal(policyConfigResp.HttpHeaderPolicyJSON, policyConfig)
if err != nil {
this.ErrorPage(err)
return
@@ -48,8 +48,8 @@ func (this *DeleteAction) RunPost(params struct {
return
}
_, err = this.RPC().HTTPHeaderPolicyRPC().UpdateHTTPHeaderPolicySettingHeaders(this.AdminContext(), &pb.UpdateHTTPHeaderPolicySettingHeadersRequest{
HeaderPolicyId: params.HeaderPolicyId,
HeadersJSON: resultJSON,
HttpHeaderPolicyId: params.HeaderPolicyId,
HeadersJSON: resultJSON,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -19,12 +19,12 @@ func (this *DeleteDeletingHeaderAction) RunPost(params struct {
// 日志
defer this.CreateLog(oplogs.LevelInfo, "删除需要删除的请求HeaderHeaderPolicyId:%d, HeaderName:%s", params.HeaderPolicyId, params.HeaderName)
policyConfigResp, err := this.RPC().HTTPHeaderPolicyRPC().FindEnabledHTTPHeaderPolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPHeaderPolicyConfigRequest{HeaderPolicyId: params.HeaderPolicyId})
policyConfigResp, err := this.RPC().HTTPHeaderPolicyRPC().FindEnabledHTTPHeaderPolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPHeaderPolicyConfigRequest{HttpHeaderPolicyId: params.HeaderPolicyId})
if err != nil {
this.ErrorPage(err)
return
}
policyConfigJSON := policyConfigResp.HeaderPolicyJSON
policyConfigJSON := policyConfigResp.HttpHeaderPolicyJSON
policyConfig := &shared.HTTPHeaderPolicy{}
err = json.Unmarshal(policyConfigJSON, policyConfig)
if err != nil {
@@ -40,8 +40,8 @@ func (this *DeleteDeletingHeaderAction) RunPost(params struct {
headerNames = append(headerNames, h)
}
_, err = this.RPC().HTTPHeaderPolicyRPC().UpdateHTTPHeaderPolicyDeletingHeaders(this.AdminContext(), &pb.UpdateHTTPHeaderPolicyDeletingHeadersRequest{
HeaderPolicyId: params.HeaderPolicyId,
HeaderNames: headerNames,
HttpHeaderPolicyId: params.HeaderPolicyId,
HeaderNames: headerNames,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -47,7 +47,7 @@ func (this *IndexAction) RunGet(params struct {
this.ErrorPage(err)
return
}
headerPolicyId := createHeaderPolicyResp.HeaderPolicyId
var headerPolicyId = createHeaderPolicyResp.HttpHeaderPolicyId
ref := &shared.HTTPHeaderPolicyRef{
IsPrior: false,
IsOn: true,
@@ -74,7 +74,7 @@ func (this *IndexAction) RunGet(params struct {
this.ErrorPage(err)
return
}
headerPolicyId := createHeaderPolicyResp.HeaderPolicyId
headerPolicyId := createHeaderPolicyResp.HttpHeaderPolicyId
ref := &shared.HTTPHeaderPolicyRef{
IsPrior: false,
IsOn: true,

View File

@@ -19,6 +19,7 @@ func init() {
GetPost("/createDeletePopup", new(CreateDeletePopupAction)).
Post("/deleteDeletingHeader", new(DeleteDeletingHeaderAction)).
Post("/delete", new(DeleteAction)).
GetPost("/updateCORSPopup", new(UpdateCORSPopupAction)).
EndAll()
})
}

View File

@@ -0,0 +1,75 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package headers
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/actions"
)
type UpdateCORSPopupAction struct {
actionutils.ParentAction
}
func (this *UpdateCORSPopupAction) Init() {
this.Nav("", "", "")
}
func (this *UpdateCORSPopupAction) RunGet(params struct {
HeaderPolicyId int64
}) {
this.Data["headerPolicyId"] = params.HeaderPolicyId
resp, err := this.RPC().HTTPHeaderPolicyRPC().FindEnabledHTTPHeaderPolicyConfig(this.AdminContext(), &pb.FindEnabledHTTPHeaderPolicyConfigRequest{HttpHeaderPolicyId: params.HeaderPolicyId})
if err != nil {
this.ErrorPage(err)
return
}
var headerPolicyJSON = resp.HttpHeaderPolicyJSON
var headerPolicy = &shared.HTTPHeaderPolicy{}
if len(headerPolicyJSON) > 0 {
err = json.Unmarshal(headerPolicyJSON, headerPolicy)
if err != nil {
this.ErrorPage(err)
return
}
}
this.Data["cors"] = headerPolicy.CORS
this.Show()
}
func (this *UpdateCORSPopupAction) RunPost(params struct {
HeaderPolicyId int64
CorsJSON []byte
Must *actions.Must
CSRF *actionutils.CSRF
}) {
var config = &shared.HTTPCORSHeaderConfig{}
err := json.Unmarshal(params.CorsJSON, config)
if err != nil {
this.Fail("配置校验失败:" + err.Error())
return
}
err = config.Init()
if err != nil {
this.Fail("配置校验失败:" + err.Error())
return
}
_, err = this.RPC().HTTPHeaderPolicyRPC().UpdateHTTPHeaderPolicyCORS(this.AdminContext(), &pb.UpdateHTTPHeaderPolicyCORSRequest{
HttpHeaderPolicyId: params.HeaderPolicyId,
CorsJSON: params.CorsJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -31,7 +31,7 @@ func (this *IndexAction) RunGet(params struct {
if !isOk {
return
}
httpsConfig := &serverconfigs.HTTPSProtocolConfig{}
var httpsConfig = &serverconfigs.HTTPSProtocolConfig{}
if len(server.HttpsJSON) > 0 {
err := json.Unmarshal(server.HttpsJSON, httpsConfig)
if err != nil {
@@ -44,12 +44,15 @@ func (this *IndexAction) RunGet(params struct {
var sslPolicy *sslconfigs.SSLPolicy
if httpsConfig.SSLPolicyRef != nil && httpsConfig.SSLPolicyRef.SSLPolicyId > 0 {
sslPolicyConfigResp, err := this.RPC().SSLPolicyRPC().FindEnabledSSLPolicyConfig(this.AdminContext(), &pb.FindEnabledSSLPolicyConfigRequest{SslPolicyId: httpsConfig.SSLPolicyRef.SSLPolicyId})
sslPolicyConfigResp, err := this.RPC().SSLPolicyRPC().FindEnabledSSLPolicyConfig(this.AdminContext(), &pb.FindEnabledSSLPolicyConfigRequest{
SslPolicyId: httpsConfig.SSLPolicyRef.SSLPolicyId,
IgnoreData: true,
})
if err != nil {
this.ErrorPage(err)
return
}
sslPolicyConfigJSON := sslPolicyConfigResp.SslPolicyJSON
var sslPolicyConfigJSON = sslPolicyConfigResp.SslPolicyJSON
if len(sslPolicyConfigJSON) > 0 {
sslPolicy = &sslconfigs.SSLPolicy{}
err = json.Unmarshal(sslPolicyConfigJSON, sslPolicy)

View File

@@ -42,7 +42,10 @@ func (this *IndexAction) RunGet(params struct {
this.Data["clusters"] = clusterMaps
// 当前服务信息
serverResp, err := this.RPC().ServerRPC().FindEnabledServer(this.AdminContext(), &pb.FindEnabledServerRequest{ServerId: params.ServerId})
serverResp, err := this.RPC().ServerRPC().FindEnabledServer(this.AdminContext(), &pb.FindEnabledServerRequest{
ServerId: params.ServerId,
IgnoreSSLCerts: true,
})
if err != nil {
this.ErrorPage(err)
return
@@ -121,6 +124,7 @@ func (this *IndexAction) RunGet(params struct {
// RunPost 保存
func (this *IndexAction) RunPost(params struct {
ServerId int64
UserId int64
Name string
Description string
ClusterId int64
@@ -157,16 +161,28 @@ func (this *IndexAction) RunPost(params struct {
return
}
// 修改套餐
if params.UserPlanId > 0 {
_, err = this.RPC().ServerRPC().UpdateServerUserPlan(this.AdminContext(), &pb.UpdateServerUserPlanRequest{
ServerId: params.ServerId,
UserPlanId: params.UserPlanId,
// 修改用户
if params.UserId > 0 {
_, err = this.RPC().ServerRPC().UpdateServerUser(this.AdminContext(), &pb.UpdateServerUserRequest{
ServerId: params.ServerId,
UserId: params.UserId,
})
if err != nil {
this.ErrorPage(err)
return
}
} else {
// 修改套餐
if params.UserPlanId > 0 {
_, err = this.RPC().ServerRPC().UpdateServerUserPlan(this.AdminContext(), &pb.UpdateServerUserPlanRequest{
ServerId: params.ServerId,
UserPlanId: params.UserPlanId,
})
if err != nil {
this.ErrorPage(err)
return
}
}
}
this.Success()

View File

@@ -36,7 +36,7 @@ func (this *IndexAction) RunGet(params struct {
this.ErrorPage(err)
return
}
headerPolicyId := createHeaderPolicyResp.HeaderPolicyId
headerPolicyId := createHeaderPolicyResp.HttpHeaderPolicyId
ref := &shared.HTTPHeaderPolicyRef{
IsPrior: false,
IsOn: true,
@@ -59,7 +59,7 @@ func (this *IndexAction) RunGet(params struct {
this.ErrorPage(err)
return
}
headerPolicyId := createHeaderPolicyResp.HeaderPolicyId
headerPolicyId := createHeaderPolicyResp.HttpHeaderPolicyId
ref := &shared.HTTPHeaderPolicyRef{
IsPrior: false,
IsOn: true,

View File

@@ -109,6 +109,12 @@ func (this *LocationHelper) createMenus(serverIdString string, locationIdString
"isActive": secondMenuItem == "referer",
"isOn": locationConfig.Web != nil && locationConfig.Web.Referers != nil && locationConfig.Web.Referers.IsPrior,
})
menuItems = append(menuItems, maps.Map{
"name": "UA名单",
"url": "/servers/server/settings/locations/userAgent?serverId=" + serverIdString + "&locationId=" + locationIdString,
"isActive": secondMenuItem == "userAgent",
"isOn": locationConfig.Web != nil && locationConfig.Web.UserAgent != nil && locationConfig.Web.UserAgent.IsPrior,
})
menuItems = append(menuItems, maps.Map{
"name": "字符编码",
"url": "/servers/server/settings/locations/charset?serverId=" + serverIdString + "&locationId=" + locationIdString,

View File

@@ -1,6 +1,6 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package uam
package referers
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"

View File

@@ -1,4 +1,4 @@
package uam
package referers
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"

View File

@@ -0,0 +1,62 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package userAgent
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/actions"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "setting", "index")
this.SecondMenu("userAgent")
}
func (this *IndexAction) RunGet(params struct {
LocationId int64
}) {
webConfig, err := dao.SharedHTTPWebDAO.FindWebConfigWithLocationId(this.AdminContext(), params.LocationId)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["webId"] = webConfig.Id
var userAgentConfig = webConfig.UserAgent
if userAgentConfig == nil {
userAgentConfig = serverconfigs.NewUserAgentConfig()
}
this.Data["userAgentConfig"] = userAgentConfig
this.Show()
}
func (this *IndexAction) RunPost(params struct {
WebId int64
UserAgentJSON []byte
Must *actions.Must
CSRF *actionutils.CSRF
}) {
defer this.CreateLogInfo("修改Web %d User-Agent设置", params.WebId)
_, err := this.RPC().HTTPWebRPC().UpdateHTTPWebUserAgent(this.AdminContext(), &pb.UpdateHTTPWebUserAgentRequest{
HttpWebId: params.WebId,
UserAgentJSON: params.UserAgentJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,22 @@
package userAgent
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/locationutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/serverutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)).
Helper(locationutils.NewLocationHelper()).
Helper(serverutils.NewServerHelper()).
Data("tinyMenuItem", "userAgent").
Prefix("/servers/server/settings/locations/userAgent").
GetPost("", new(IndexAction)).
EndAll()
})
}

View File

@@ -1,6 +1,6 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package uam
package referers
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"

View File

@@ -1,4 +1,4 @@
package uam
package referers
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"

View File

@@ -0,0 +1,64 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package userAgent
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/dao"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/iwind/TeaGo/actions"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "setting", "index")
this.SecondMenu("userAgent")
}
func (this *IndexAction) RunGet(params struct {
ServerId int64
}) {
this.Data["serverId"] = params.ServerId
webConfig, err := dao.SharedHTTPWebDAO.FindWebConfigWithServerId(this.AdminContext(), params.ServerId)
if err != nil {
this.ErrorPage(err)
return
}
this.Data["webId"] = webConfig.Id
var userAgentConfig = webConfig.UserAgent
if userAgentConfig == nil {
userAgentConfig = serverconfigs.NewUserAgentConfig()
}
this.Data["userAgentConfig"] = userAgentConfig
this.Show()
}
func (this *IndexAction) RunPost(params struct {
WebId int64
UserAgentJSON []byte
Must *actions.Must
CSRF *actionutils.CSRF
}) {
defer this.CreateLogInfo("修改Web %d User-Agent设置", params.WebId)
_, err := this.RPC().HTTPWebRPC().UpdateHTTPWebUserAgent(this.AdminContext(), &pb.UpdateHTTPWebUserAgentRequest{
HttpWebId: params.WebId,
UserAgentJSON: params.UserAgentJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}

View File

@@ -0,0 +1,19 @@
package userAgent
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/serverutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)).
Helper(serverutils.NewServerHelper()).
Prefix("/servers/server/settings/userAgent").
GetPost("", new(IndexAction)).
EndAll()
})
}

View File

@@ -57,7 +57,10 @@ func (this *ServerHelper) createLeftMenu(action *actions.ActionObject) {
return
}
serverResp, err := rpcClient.ServerRPC().FindEnabledServer(rpcClient.Context(action.Context.GetInt64("adminId")), &pb.FindEnabledServerRequest{ServerId: serverId})
serverResp, err := rpcClient.ServerRPC().FindEnabledServer(rpcClient.Context(action.Context.GetInt64("adminId")), &pb.FindEnabledServerRequest{
ServerId: serverId,
IgnoreSSLCerts: true,
})
if err != nil {
logs.Error(err)
return
@@ -315,6 +318,12 @@ func (this *ServerHelper) createSettingsMenu(secondMenuItem string, serverIdStri
"isActive": secondMenuItem == "referer",
"isOn": serverConfig.Web != nil && serverConfig.Web.Referers != nil && serverConfig.Web.Referers.IsOn,
})
menuItems = append(menuItems, maps.Map{
"name": "UA名单",
"url": "/servers/server/settings/userAgent?serverId=" + serverIdString,
"isActive": secondMenuItem == "userAgent",
"isOn": serverConfig.Web != nil && serverConfig.Web.UserAgent != nil && serverConfig.Web.UserAgent.IsOn,
})
menuItems = append(menuItems, maps.Map{
"name": "字符编码",
"url": "/servers/server/settings/charset?serverId=" + serverIdString,

View File

@@ -8,14 +8,17 @@ import (
"strconv"
)
// 查找Server
// FindServer 查找服务信息
func FindServer(p *actionutils.ParentAction, serverId int64) (*pb.Server, *serverconfigs.ServerConfig, bool) {
serverResp, err := p.RPC().ServerRPC().FindEnabledServer(p.AdminContext(), &pb.FindEnabledServerRequest{ServerId: serverId})
serverResp, err := p.RPC().ServerRPC().FindEnabledServer(p.AdminContext(), &pb.FindEnabledServerRequest{
ServerId: serverId,
IgnoreSSLCerts: true,
})
if err != nil {
p.ErrorPage(err)
return nil, nil, false
}
server := serverResp.Server
var server = serverResp.Server
if server == nil {
p.ErrorPage(errors.New("not found server with id '" + strconv.FormatInt(serverId, 10) + "'"))
return nil, nil, false

View File

@@ -8,6 +8,7 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/conds/condutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/actions"
@@ -123,6 +124,16 @@ func (this *ComponentsAction) RunGet(params struct{}) {
buffer.Write([]byte{'\n', '\n'})
}
// WAF操作符
wafOperatorsJSON, err := json.Marshal(firewallconfigs.AllRuleOperators)
if err != nil {
logs.Println("ComponentsAction marshal waf rule operators failed: " + err.Error())
} else {
buffer.WriteString("window.WAF_RULE_OPERATORS = ")
buffer.Write(wafOperatorsJSON)
buffer.Write([]byte{'\n', '\n'})
}
componentsData = buffer.Bytes()
// ETag

View File

@@ -97,6 +97,7 @@ func (this *UserAction) RunGet(params struct {
"username": user.Username,
"fullname": user.Fullname,
"email": user.Email,
"verifiedEmail": user.VerifiedEmail,
"tel": user.Tel,
"remark": user.Remark,
"mobile": user.Mobile,

View File

@@ -118,16 +118,16 @@ func FindAllMenuMaps(nodeLogsType string, countUnreadNodeLogs int64, countUnread
"subtitle": "集群列表",
"icon": "globe",
"subItems": []maps.Map{
{
"name": "问题修复",
"url": "/dns/issues",
"code": "issue",
},
{
"name": "DNS服务商",
"url": "/dns/providers",
"code": "provider",
},
{
"name": "问题修复",
"url": "/dns/issues",
"code": "issue",
},
},
},
{

View File

@@ -112,8 +112,8 @@ func checkIPWithoutCache(config *systemconfigs.SecurityConfig, ipAddr string) bo
}
// 请求检查相关正则
var searchEngineRegex = regexp.MustCompile(`60spider|adldxbot|adsbot-google|applebot|admantx|alexa|baidu|bingbot|bingpreview|facebookexternalhit|googlebot|proximic|slurp|sogou|twitterbot|yandex`)
var spiderRegexp = regexp.MustCompile(`python|pycurl|http-client|httpclient|apachebench|nethttp|http_request|java|perl|ruby|scrapy|php|rust|curl|wget`) // 其中增加了curl和wget
var searchEngineRegex = regexp.MustCompile(`(?i)(60spider|adldxbot|adsbot-google|applebot|admantx|alexa|baidu|bingbot|bingpreview|facebookexternalhit|googlebot|proximic|slurp|sogou|twitterbot|yandex)`)
var spiderRegexp = regexp.MustCompile(`(?i)(python|pycurl|http-client|httpclient|apachebench|nethttp|http_request|java|perl|ruby|scrapy|php|rust|curl|wget)`) // 其中增加了curl和wget
// 检查请求
func checkRequestSecurity(securityConfig *systemconfigs.SecurityConfig, req *http.Request) bool {

View File

@@ -84,6 +84,7 @@ import (
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/reverseProxy"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/rewrite"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/stat"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/userAgent"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/waf"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/web"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/locations/webp"
@@ -102,6 +103,7 @@ import (
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/tls"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/udp"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/unix"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/userAgent"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/waf"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/web"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/server/settings/webp"

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -2,6 +2,7 @@
* 更多选项
*/
Vue.component("more-options-indicator", {
props:[],
data: function () {
return {
visible: false
@@ -14,6 +15,7 @@ Vue.component("more-options-indicator", {
Tea.Vue.moreOptionsVisible = this.visible
}
this.$emit("change", this.visible)
this.$emit("input", this.visible)
}
},
template: '<a href="" style="font-weight: normal" @click.prevent="changeVisible()"><slot><span v-if="!visible">更多选项</span><span v-if="visible">收起选项</span></slot> <i class="icon angle" :class="{down:!visible, up:visible}"></i> </a>'

View File

@@ -1,5 +1,5 @@
Vue.component("values-box", {
props: ["values", "v-values", "size", "maxlength", "name", "placeholder"],
props: ["values", "v-values", "size", "maxlength", "name", "placeholder", "v-allow-empty"],
data: function () {
let values = this.values;
if (values == null) {
@@ -39,7 +39,9 @@ Vue.component("values-box", {
},
confirm: function () {
if (this.value.length == 0) {
return
if (typeof(this.vAllowEmpty) != "boolean" || !this.vAllowEmpty) {
return
}
}
if (this.isUpdating) {
@@ -75,12 +77,17 @@ Vue.component("values-box", {
},
template: `<div>
<div v-show="!isEditing && realValues.length > 0">
<div class="ui label tiny basic" v-for="(value, index) in realValues" style="margin-top:0.4em;margin-bottom:0.4em">{{value}}</div>
<div class="ui label tiny basic" v-for="(value, index) in realValues" style="margin-top:0.4em;margin-bottom:0.4em">
<span v-if="value.toString().length > 0">{{value}}</span>
<span v-if="value.toString().length == 0" class="disabled">[空]</span>
</div>
<a href="" @click.prevent="startEditing" style="font-size: 0.8em; margin-left: 0.2em">[修改]</a>
</div>
<div v-show="isEditing || realValues.length == 0">
<div style="margin-bottom: 1em" v-if="realValues.length > 0">
<div class="ui label tiny basic" v-for="(value, index) in realValues" style="margin-top:0.4em;margin-bottom:0.4em">{{value}}
<div class="ui label tiny basic" v-for="(value, index) in realValues" style="margin-top:0.4em;margin-bottom:0.4em">
<span v-if="value.toString().length > 0">{{value}}</span>
<span v-if="value.toString().length == 0" class="disabled">[空]</span>
<input type="hidden" :name="name" :value="value"/>
&nbsp; <a href="" @click.prevent="update(index)" title="修改"><i class="icon pencil small" ></i></a>
<a href="" @click.prevent="remove(index)" title="删除"><i class="icon remove"></i></a>

View File

@@ -80,7 +80,7 @@ Vue.component("dns-route-selector", {
return
}
this.searchingRoutes = this.vAllRoutes.filter(function (route) {
return teaweb.match(route.name, keyword) || teaweb.match(route.domainName, keyword)
return teaweb.match(route.name, keyword) || teaweb.match(route.code, keyword) || teaweb.match(route.domainName, keyword)
})
if (this.searchingRoutes.length > 0) {
this.routeCode = this.searchingRoutes[0].code + "@" + this.searchingRoutes[0].domainId
@@ -99,24 +99,25 @@ Vue.component("dns-route-selector", {
</div>
<button type="button" class="ui button small" @click.prevent="add" v-if="!isAdding">+</button>
<div v-if="isAdding">
<div class="ui fields inline">
<div class="ui field">
<select class="ui dropdown" style="width: 18em" v-model="routeCode">
<option value="" v-if="keyword.length == 0">[请选择]</option>
<option v-for="route in searchingRoutes" :value="route.code + '@' + route.domainId">{{route.name}}{{route.domainName}}</option>
</select>
</div>
<div class="ui field">
<input type="text" placeholder="搜索..." size="10" v-model="keyword" ref="keywordRef" @keyup.enter="confirm" @keypress.enter.prevent="1"/>
</div>
<div class="ui field">
<button class="ui button tiny" type="button" @click.prevent="confirm">确定</button>
</div>
<div class="ui field">
<a href="" @click.prevent="cancel()"><i class="icon remove small"></i></a>
</div>
</div>
<table class="ui table">
<tr>
<td class="title">所有线路</td>
<td>
<select class="ui dropdown auto-width" v-model="routeCode">
<option value="" v-if="keyword.length == 0">[请选择]</option>
<option v-for="route in searchingRoutes" :value="route.code + '@' + route.domainId">{{route.name}}{{route.code}}/{{route.domainName}}</option>
</select>
</td>
</tr>
<tr>
<td>搜索</td>
<td>
<input type="text" placeholder="搜索..." size="10" style="width: 10em" v-model="keyword" ref="keywordRef" @keyup.enter="confirm" @keypress.enter.prevent="1"/>
</td>
</tr>
</table>
<button class="ui button tiny" type="button" @click.prevent="confirm">确定</button> &nbsp; <a href="" @click.prevent="cancel()"><i class="icon remove small"></i></a>
</div>
</div>`
})

View File

@@ -26,7 +26,8 @@ Vue.component("ns-route-ranges-box", {
// region
regions: [],
regionType: "country"
regionType: "country",
regionConnector: "OR"
}
},
methods: {
@@ -68,6 +69,7 @@ Vue.component("ns-route-ranges-box", {
this.isAdding = false
this.regions = []
this.regionType = "country"
this.regionConnector = "OR"
this.isReverse = false
},
confirmIPRange: function () {
@@ -131,6 +133,7 @@ Vue.component("ns-route-ranges-box", {
}
this.ranges.push({
type: "region",
connector: this.regionConnector,
params: {
regions: this.regions,
isReverse: this.isReverse
@@ -362,10 +365,24 @@ Vue.component("ns-route-ranges-box", {
<span class="red" v-if="range.params.isReverse">[排除]</span>
<span v-if="range.type == 'ipRange'">IP范围</span>
<span v-if="range.type == 'cidr'">CIDR</span>
<span v-if="range.type == 'region'">区域:</span>
<span v-if="range.type == 'region'"></span>
<span v-if="range.type == 'ipRange'">{{range.params.ipFrom}} - {{range.params.ipTo}}</span>
<span v-if="range.type == 'cidr'">{{range.params.cidr}}</span>
<span v-if="range.type == 'region'"><span v-for="(region, index) in range.params.regions">{{region.name}}<span v-if="index < range.params.regions.length - 1"></span></span></span>
<span v-if="range.type == 'region'">
<span v-for="(region, index) in range.params.regions">
<span v-if="region.type == 'country'">国家/地区</span>
<span v-if="region.type == 'province'">省份</span>
<span v-if="region.type == 'city'">城市</span>
<span v-if="region.type == 'provider'">ISP</span>
{{region.name}}
<span v-if="index < range.params.regions.length - 1" class="grey">
&nbsp;
<span v-if="range.connector == 'OR' || range.connector == '' || range.connector == null">或</span>
<span v-if="range.connector == 'AND'">且</span>
&nbsp;
</span>
</span>
</span>
&nbsp; <a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
</div>
<div class="ui divider"></div>
@@ -488,9 +505,21 @@ Vue.component("ns-route-ranges-box", {
<tr>
<td>已添加</td>
<td>
<div v-for="(region, index) in regions" class="ui label small basic">
{{region.name}} <a href="" title="删除" @click.prevent="removeRegion(index)"><i class="icon remove small"></i></a>
</div>
<span v-for="(region, index) in regions">
<span class="ui label small basic">
<span v-if="region.type == 'country'">国家/地区</span>
<span v-if="region.type == 'province'">省份</span>
<span v-if="region.type == 'city'">城市</span>
<span v-if="region.type == 'provider'">ISP</span>
{{region.name}} <a href="" title="删除" @click.prevent="removeRegion(index)"><i class="icon remove small"></i></a>
</span>
<span v-if="index < regions.length - 1" class="grey">
&nbsp;
<span v-if="regionConnector == 'OR' || regionConnector == ''">或</span>
<span v-if="regionConnector == 'AND'">且</span>
&nbsp;
</span>
</span>
</td>
</tr>
<tr>
@@ -526,6 +555,17 @@ Vue.component("ns-route-ranges-box", {
</div>
</td>
</tr>
<tr>
<td>区域之间关系</td>
<td>
<select class="ui dropdown auto-width" v-model="regionConnector">
<option value="OR">或</option>
<option value="AND">且</option>
</select>
<p class="comment" v-if="regionConnector == 'OR'">匹配所选任一区域即认为匹配成功。</p>
<p class="comment" v-if="regionConnector == 'AND'">匹配所有所选区域才认为匹配成功。</p>
</td>
</tr>
<tr>
<td>排除</td>
<td>

View File

@@ -88,6 +88,7 @@ Vue.component("ns-routes-selector", {
<option value="isp">运营商</option>
<option value="china">中国省市</option>
<option value="world">全球国家地区</option>
<option value="agent">搜索引擎</option>
</select>
</div>

View File

@@ -0,0 +1,102 @@
Vue.component("email-sender", {
props: ["value", "name"],
data: function () {
let value = this.value
if (value == null) {
value = {
isOn: false,
smtpHost: "",
smtpPort: 0,
username: "",
password: "",
fromEmail: "",
fromName: ""
}
}
let smtpPortString = value.smtpPort.toString()
if (smtpPortString == "0") {
smtpPortString = ""
}
return {
config: value,
smtpPortString: smtpPortString
}
},
watch: {
smtpPortString: function (v) {
let port = parseInt(v)
if (!isNaN(port)) {
this.config.smtpPort = port
}
}
},
methods: {
test: function () {
window.TESTING_EMAIL_CONFIG = this.config
teaweb.popup("/users/setting/emailTest", {
height: "36em"
})
}
},
template: `<div>
<input type="hidden" :name="name" :value="JSON.stringify(config)"/>
<table class="ui table selectable definition">
<tbody>
<tr>
<td class="title">启用</td>
<td><checkbox v-model="config.isOn"></checkbox></td>
</tr>
</tbody>
<tbody v-show="config.isOn">
<tr>
<td>SMTP地址 *</td>
<td>
<input type="text" :name="name + 'SmtpHost'" v-model="config.smtpHost"/>
<p class="comment">SMTP主机地址比如<code-label>smtp.qq.com</code-label>目前仅支持TLS协议如不清楚请查询对应邮件服务商文档。</p>
</td>
</tr>
<tr>
<td>SMTP端口 *</td>
<td>
<input type="text" :name="name + 'SmtpPort'" v-model="smtpPortString" style="width: 5em" maxlength="5"/>
<p class="comment">SMTP主机端口比如<code-label>587</code-label>、<code-label>465</code-label>,如不清楚,请查询对应邮件服务商文档。</p>
</td>
</tr>
<tr>
<td>用户名 *</td>
<td>
<input type="text" :name="name + 'Username'" v-model="config.username"/>
<p class="comment">通常为发件人邮箱地址。</p>
</td>
</tr>
<tr>
<td>密码 *</td>
<td>
<input type="password" :name="name + 'Password'" v-model="config.password"/>
<p class="comment">邮箱登录密码或授权码,如不清楚,请查询对应邮件服务商文档。。</p>
</td>
</tr>
<tr>
<td>发件人Email *</td>
<td>
<input type="text" :name="name + 'FromEmail'" v-model="config.fromEmail" maxlength="128"/>
<p class="comment">使用的发件人邮箱地址,通常和发件用户名一致。</p>
</td>
</tr>
<tr>
<td>发件人名称</td>
<td>
<input type="text" :name="name + 'FromName'" v-model="config.fromName" maxlength="30"/>
<p class="comment">使用的发件人名称,默认使用系统设置的<a href="/settings/ui" target="_blank">产品名称</a>。</p>
</td>
</tr>
<tr>
<td>发送测试</td>
<td><a href="" @click.prevent="test">[点此测试]</a></td>
</tr>
</tbody>
</table>
<div class="margin"></div>
</div>`
})

View File

@@ -20,11 +20,13 @@ Vue.component("http-compression-config-box", {
gzipRef: null,
deflateRef: null,
brotliRef: null,
minLength: {count: 0, "unit": "kb"},
maxLength: {count: 0, "unit": "kb"},
minLength: {count: 1, "unit": "kb"},
maxLength: {count: 32, "unit": "mb"},
mimeTypes: ["text/*", "application/javascript", "application/json", "application/atom+xml", "application/rss+xml", "application/xhtml+xml", "font/*", "image/svg+xml"],
extensions: [".js", ".json", ".html", ".htm", ".xml", ".css", ".woff2", ".txt"],
conds: null
exceptExtensions: [".apk", ".ipa"],
conds: null,
enablePartialContent: false
}
}
@@ -108,6 +110,14 @@ Vue.component("http-compression-config-box", {
})
this.config.extensions = values
},
changeExceptExtensions: function (values) {
values.forEach(function (v, k) {
if (v.length > 0 && v[0] != ".") {
values[k] = "." + v
}
})
this.config.exceptExtensions = values
},
changeMimeTypes: function (values) {
this.config.mimeTypes = values
},
@@ -179,6 +189,13 @@ Vue.component("http-compression-config-box", {
<p class="comment">含有这些扩展名的URL将会被压缩不区分大小写。</p>
</td>
</tr>
<tr>
<td>例外扩展名</td>
<td>
<values-box :values="config.exceptExtensions" @change="changeExceptExtensions" placeholder="比如 .html"></values-box>
<p class="comment">含有这些扩展名的URL将<strong>不会</strong>被压缩,不区分大小写。</p>
</td>
</tr>
<tr>
<td>支持的MimeType</td>
<td>
@@ -231,6 +248,13 @@ Vue.component("http-compression-config-box", {
<p class="comment">0表示不限制内容长度从文件尺寸或Content-Length中获取。</p>
</td>
</tr>
<tr>
<td>支持Partial<br/>Content</td>
<td>
<checkbox v-model="config.enablePartialContent"></checkbox>
<p class="comment">支持对分区内容PartialContent的压缩除非客户端有特殊要求一般不需要启用。</p>
</td>
</tr>
<tr>
<td>匹配条件</td>
<td>

View File

@@ -744,7 +744,7 @@ Vue.component("http-cond-params", {
<select class="ui dropdown auto-width" v-model="operator" @change="changeOperator">
<option v-for="operator in operators" :value="operator.op">{{operator.name}}</option>
</select>
<p class="comment">{{operatorDescription}}</p>
<p class="comment" v-html="operatorDescription"></p>
</div>
</td>
</tr>

View File

@@ -0,0 +1,34 @@
Vue.component("http-cors-header-config-box", {
props: ["value"],
data: function () {
let config = this.value
if (config == null) {
config = {
isOn: false,
allowMethods: [],
allowOrigin: "",
allowCredentials: true,
exposeHeaders: [],
maxAge: 0,
requestHeaders: [],
requestMethod: ""
}
}
return {
config: config
}
},
template: `<div>
<input type="hidden" name="corsJSON" :value="JSON.stringify(config)"/>
<table class="ui table definition selectable">
<tr>
<td class="title">启用CORS自适应跨域</td>
<td>
<checkbox v-model="config.isOn"></checkbox>
</td>
</tr>
</table>
<div class="margin"></div>
</div>`
})

View File

@@ -10,7 +10,18 @@ Vue.component("http-firewall-rule-label", {
showErr: function (err) {
teaweb.popupTip("规则校验错误,请修正:<span class=\"red\">" + teaweb.encodeHTML(err) + "</span>")
},
operatorName: function (operatorCode) {
var operatorName = operatorCode
if (typeof (window.WAF_RULE_OPERATORS) != null) {
window.WAF_RULE_OPERATORS.forEach(function (v) {
if (v.code == operatorCode) {
operatorName = v.name
}
})
}
return operatorName
}
},
template: `<div>
<div class="ui label tiny basic" style="line-height: 1.5">
@@ -29,7 +40,7 @@ Vue.component("http-firewall-rule-label", {
<span v-else>
<span v-if="rule.paramFilters != null && rule.paramFilters.length > 0" v-for="paramFilter in rule.paramFilters"> | {{paramFilter.code}}</span>
<var :class="{dash:rule.isCaseInsensitive}" :title="rule.isCaseInsensitive ? '大小写不敏感':''" v-if="!rule.isComposed">{{rule.operator}}</var>
<span :class="{dash:rule.isCaseInsensitive}" :title="rule.isCaseInsensitive ? '大小写不敏感':''" v-if="!rule.isComposed">{{operatorName(rule.operator)}}</span>
{{rule.value}}
</span>

View File

@@ -21,7 +21,7 @@ Vue.component("http-firewall-rules-box", {
})
},
updateRule: function (index, rule) {
window.UPDATING_RULE = rule
window.UPDATING_RULE = teaweb.clone(rule)
let that = this
teaweb.popup("/servers/components/waf/createRulePopup?type=" + this.vType, {
height: "30em",
@@ -35,12 +35,24 @@ Vue.component("http-firewall-rules-box", {
teaweb.confirm("确定要删除此规则吗?", function () {
that.rules.$remove(index)
})
},
operatorName: function (operatorCode) {
var operatorName = operatorCode
if (typeof (window.WAF_RULE_OPERATORS) != null) {
window.WAF_RULE_OPERATORS.forEach(function (v) {
if (v.code == operatorCode) {
operatorName = v.name
}
})
}
return operatorName
}
},
template: `<div>
<input type="hidden" name="rulesJSON" :value="JSON.stringify(rules)"/>
<div v-if="rules.length > 0">
<div v-for="(rule, index) in rules" class="ui label small basic" style="margin-bottom: 0.5em">
<div v-for="(rule, index) in rules" class="ui label small basic" style="margin-bottom: 0.5em; line-height: 1.5">
{{rule.name}}[{{rule.param}}]
<!-- cc2 -->
@@ -55,7 +67,7 @@ Vue.component("http-firewall-rules-box", {
</span>
<span v-else>
<span v-if="rule.paramFilters != null && rule.paramFilters.length > 0" v-for="paramFilter in rule.paramFilters"> | {{paramFilter.code}}</span> <var>{{rule.operator}}</var> {{rule.value}}
<span v-if="rule.paramFilters != null && rule.paramFilters.length > 0" v-for="paramFilter in rule.paramFilters"> | {{paramFilter.code}}</span> <span :class="{dash:rule.isCaseInsensitive}" :title="rule.isCaseInsensitive ? '大小写不敏感':''">{{operatorName(rule.operator)}}</span> {{rule.value}}
</span>
<!-- description -->

View File

@@ -28,7 +28,7 @@ Vue.component("http-header-assistant", {
}
this.matchedHeaders = this.allHeaders.filter(function (header) {
return teaweb.match(header, v)
}).slice(0, 5)
}).slice(0, 10)
}
},
methods: {
@@ -38,7 +38,7 @@ Vue.component("http-header-assistant", {
}
},
template: `<span v-if="selectedHeaderName.length == 0">
<a href="" v-for="header in matchedHeaders" class="ui label basic tiny blue" style="font-weight: normal" @click.prevent="select(header)">{{header}}</a>
<a href="" v-for="header in matchedHeaders" class="ui label basic tiny blue" style="font-weight: normal; margin-bottom: 0.3em" @click.prevent="select(header)">{{header}}</a>
<span v-if="matchedHeaders.length > 0">&nbsp; &nbsp;</span>
</span>`
})

View File

@@ -54,6 +54,13 @@ Vue.component("http-header-policy-box", {
}
}
let responseCORS = {
isOn: false
}
if (responsePolicy.cors != null) {
responseCORS = responsePolicy.cors
}
return {
type: type,
typeName: (type == "request") ? "请求" : "响应",
@@ -62,7 +69,8 @@ Vue.component("http-header-policy-box", {
requestSettingHeaders: requestSettingHeaders,
requestDeletingHeaders: requestDeletingHeaders,
responseSettingHeaders: responseSettingHeaders,
responseDeletingHeaders: responseDeletingHeaders
responseDeletingHeaders: responseDeletingHeaders,
responseCORS: responseCORS
}
},
methods: {
@@ -114,6 +122,13 @@ Vue.component("http-header-policy-box", {
.refresh()
}
)
},
updateCORS: function (policyId) {
teaweb.popup("/servers/server/settings/headers/updateCORSPopup?" + this.vParams + "&headerPolicyId=" + policyId + "&type=" + this.type, {
callback: function () {
teaweb.successRefresh("保存成功")
}
})
}
},
template: `<div>
@@ -141,7 +156,7 @@ Vue.component("http-header-policy-box", {
<warning-message>由于已经在当前<a :href="vGroupSettingUrl + '#request'">服务分组</a>中进行了对应的配置,在这里的配置将不会生效。</warning-message>
</div>
<div :class="{'opacity-mask': vHasGroupRequestConfig}">
<h3>设置请求Header <a href="" @click.prevent="addSettingHeader(vRequestHeaderPolicy.id)">[添加新Header]</a></h3>
<h4>设置请求Header <a href="" @click.prevent="addSettingHeader(vRequestHeaderPolicy.id)">[添加新Header]</a></h4>
<p class="comment" v-if="requestSettingHeaders.length == 0">暂时还没有Header。</p>
<table class="ui table selectable celled" v-if="requestSettingHeaders.length > 0">
<thead>
@@ -151,35 +166,39 @@ Vue.component("http-header-policy-box", {
<th class="two op">操作</th>
</tr>
</thead>
<tr v-for="header in requestSettingHeaders">
<td class="five wide">
{{header.name}}
<div>
<span v-if="header.status != null && header.status.codes != null && !header.status.always"><grey-label v-for="code in header.status.codes" :key="code">{{code}}</grey-label></span>
<span v-if="header.methods != null && header.methods.length > 0"><grey-label v-for="method in header.methods" :key="method">{{method}}</grey-label></span>
<span v-if="header.domains != null && header.domains.length > 0"><grey-label v-for="domain in header.domains" :key="domain">{{domain}}</grey-label></span>
<grey-label v-if="header.shouldAppend">附加</grey-label>
<grey-label v-if="header.disableRedirect">跳转禁用</grey-label>
<grey-label v-if="header.shouldReplace && header.replaceValues != null && header.replaceValues.length > 0">替换</grey-label>
</div>
</td>
<td>{{header.value}}</td>
<td><a href="" @click.prevent="updateSettingPopup(vRequestHeaderPolicy.id, header.id)">修改</a> &nbsp; <a href="" @click.prevent="deleteHeader(vRequestHeaderPolicy.id, 'setHeader', header.id)">删除</a> </td>
</tr>
<tbody v-for="header in requestSettingHeaders">
<tr>
<td class="five wide">
{{header.name}}
<div>
<span v-if="header.status != null && header.status.codes != null && !header.status.always"><grey-label v-for="code in header.status.codes" :key="code">{{code}}</grey-label></span>
<span v-if="header.methods != null && header.methods.length > 0"><grey-label v-for="method in header.methods" :key="method">{{method}}</grey-label></span>
<span v-if="header.domains != null && header.domains.length > 0"><grey-label v-for="domain in header.domains" :key="domain">{{domain}}</grey-label></span>
<grey-label v-if="header.shouldAppend">附加</grey-label>
<grey-label v-if="header.disableRedirect">跳转禁用</grey-label>
<grey-label v-if="header.shouldReplace && header.replaceValues != null && header.replaceValues.length > 0">替换</grey-label>
</div>
</td>
<td>{{header.value}}</td>
<td><a href="" @click.prevent="updateSettingPopup(vRequestHeaderPolicy.id, header.id)">修改</a> &nbsp; <a href="" @click.prevent="deleteHeader(vRequestHeaderPolicy.id, 'setHeader', header.id)">删除</a> </td>
</tr>
</tbody>
</table>
<h3>删除请求Header</h3>
<h4>删除请求Header</h4>
<p class="comment">这里可以设置需要从请求中删除的Header。</p>
<table class="ui table definition selectable">
<td class="title">需要删除的Header</td>
<td>
<div v-if="requestDeletingHeaders.length > 0">
<div class="ui label small basic" v-for="headerName in requestDeletingHeaders">{{headerName}} <a href=""><i class="icon remove" title="删除" @click.prevent="deleteDeletingHeader(vRequestHeaderPolicy.id, headerName)"></i></a> </div>
<div class="ui divider" ></div>
</div>
<button class="ui button small" type="button" @click.prevent="addDeletingHeader(vRequestHeaderPolicy.id, 'request')">+</button>
</td>
<tr>
<td class="title">需要删除的Header</td>
<td>
<div v-if="requestDeletingHeaders.length > 0">
<div class="ui label small basic" v-for="headerName in requestDeletingHeaders">{{headerName}} <a href=""><i class="icon remove" title="删除" @click.prevent="deleteDeletingHeader(vRequestHeaderPolicy.id, headerName)"></i></a> </div>
<div class="ui divider" ></div>
</div>
<button class="ui button small" type="button" @click.prevent="addDeletingHeader(vRequestHeaderPolicy.id, 'request')">+</button>
</td>
</tr>
</table>
</div>
</div>
@@ -199,7 +218,7 @@ Vue.component("http-header-policy-box", {
<warning-message>由于已经在当前<a :href="vGroupSettingUrl + '#response'">服务分组</a>中进行了对应的配置,在这里的配置将不会生效。</warning-message>
</div>
<div :class="{'opacity-mask': vHasGroupResponseConfig}">
<h3>设置响应Header <a href="" @click.prevent="addSettingHeader(vResponseHeaderPolicy.id)">[添加新Header]</a></h3>
<h4>设置响应Header <a href="" @click.prevent="addSettingHeader(vResponseHeaderPolicy.id)">[添加新Header]</a></h4>
<p class="comment" style="margin-top: 0; padding-top: 0">将会覆盖已有的同名Header。</p>
<p class="comment" v-if="responseSettingHeaders.length == 0">暂时还没有Header。</p>
<table class="ui table selectable celled" v-if="responseSettingHeaders.length > 0">
@@ -210,37 +229,52 @@ Vue.component("http-header-policy-box", {
<th class="two op">操作</th>
</tr>
</thead>
<tr v-for="header in responseSettingHeaders">
<td class="five wide">
{{header.name}}
<div>
<span v-if="header.status != null && header.status.codes != null && !header.status.always"><grey-label v-for="code in header.status.codes" :key="code">{{code}}</grey-label></span>
<span v-if="header.methods != null && header.methods.length > 0"><grey-label v-for="method in header.methods" :key="method">{{method}}</grey-label></span>
<span v-if="header.domains != null && header.domains.length > 0"><grey-label v-for="domain in header.domains" :key="domain">{{domain}}</grey-label></span>
<grey-label v-if="header.shouldAppend">附加</grey-label>
<grey-label v-if="header.disableRedirect">跳转禁用</grey-label>
<grey-label v-if="header.shouldReplace && header.replaceValues != null && header.replaceValues.length > 0">替换</grey-label>
</div>
</td>
<td>{{header.value}}</td>
<td><a href="" @click.prevent="updateSettingPopup(vResponseHeaderPolicy.id, header.id)">修改</a> &nbsp; <a href="" @click.prevent="deleteHeader(vResponseHeaderPolicy.id, 'setHeader', header.id)">删除</a> </td>
</tr>
<tbody v-for="header in responseSettingHeaders">
<tr>
<td class="five wide">
{{header.name}}
<div>
<span v-if="header.status != null && header.status.codes != null && !header.status.always"><grey-label v-for="code in header.status.codes" :key="code">{{code}}</grey-label></span>
<span v-if="header.methods != null && header.methods.length > 0"><grey-label v-for="method in header.methods" :key="method">{{method}}</grey-label></span>
<span v-if="header.domains != null && header.domains.length > 0"><grey-label v-for="domain in header.domains" :key="domain">{{domain}}</grey-label></span>
<grey-label v-if="header.shouldAppend">附加</grey-label>
<grey-label v-if="header.disableRedirect">跳转禁用</grey-label>
<grey-label v-if="header.shouldReplace && header.replaceValues != null && header.replaceValues.length > 0">替换</grey-label>
</div>
</td>
<td>{{header.value}}</td>
<td><a href="" @click.prevent="updateSettingPopup(vResponseHeaderPolicy.id, header.id)">修改</a> &nbsp; <a href="" @click.prevent="deleteHeader(vResponseHeaderPolicy.id, 'setHeader', header.id)">删除</a> </td>
</tr>
</tbody>
</table>
<h3>删除响应Header</h3>
<h4>删除响应Header</h4>
<p class="comment">这里可以设置需要从响应中删除的Header。</p>
<table class="ui table definition selectable">
<td class="title">需要删除的Header</td>
<td>
<div v-if="responseDeletingHeaders.length > 0">
<div class="ui label small basic" v-for="headerName in responseDeletingHeaders">{{headerName}} <a href=""><i class="icon remove" title="删除" @click.prevent="deleteDeletingHeader(vResponseHeaderPolicy.id, headerName)"></i></a> </div>
<div class="ui divider" ></div>
</div>
<button class="ui button small" type="button" @click.prevent="addDeletingHeader(vResponseHeaderPolicy.id, 'response')">+</button>
</td>
<tr>
<td class="title">需要删除的Header</td>
<td>
<div v-if="responseDeletingHeaders.length > 0">
<div class="ui label small basic" v-for="headerName in responseDeletingHeaders">{{headerName}} <a href=""><i class="icon remove" title="删除" @click.prevent="deleteDeletingHeader(vResponseHeaderPolicy.id, headerName)"></i></a> </div>
<div class="ui divider" ></div>
</div>
<button class="ui button small" type="button" @click.prevent="addDeletingHeader(vResponseHeaderPolicy.id, 'response')">+</button>
</td>
</tr>
</table>
</div>
<h4>其他设置</h4>
<table class="ui table definition selectable">
<tr>
<td class="title">CORS自适应跨域</td>
<td>
<span v-if="responseCORS.isOn" class="green">已启用</span><span class="disabled" v-else="">未启用</span> &nbsp; <a href="" @click.prevent="updateCORS(vResponseHeaderPolicy.id)">[修改]</a>
</td>
</tr>
</table>
</div>
</div>
<div class="margin"></div>
</div>`

View File

@@ -57,7 +57,7 @@ Vue.component("http-remote-addr-config-box", {
<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
<tbody v-show="(!vIsLocation && !vIsGroup) || config.isPrior">
<tr>
<td class="title">是否启用</td>
<td class="title">启用访客IP设置</td>
<td>
<div class="ui checkbox">
<input type="checkbox" value="1" v-model="config.isOn"/>

View File

@@ -62,7 +62,7 @@ Vue.component("http-request-limit-config-box", {
<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
<tbody v-show="(!vIsLocation && !vIsGroup) || config.isPrior">
<tr>
<td class="title">启用</td>
<td class="title">启用请求限制</td>
<td>
<checkbox v-model="config.isOn"></checkbox>
</td>

View File

@@ -36,7 +36,7 @@ Vue.component("script-config-box", {
<table class="ui table definition selectable">
<tbody>
<tr>
<td class="title">是否启用</td>
<td class="title">启用脚本设置</td>
<td><checkbox v-model="config.isOn"></checkbox></td>
</tr>
</tbody>

View File

@@ -43,6 +43,7 @@ Vue.component("ssl-config-box", {
}
let hsts = policy.hsts
let hstsMaxAgeString = "31536000"
if (hsts == null) {
hsts = {
isOn: false,
@@ -52,6 +53,9 @@ Vue.component("ssl-config-box", {
domains: []
}
}
if (hsts.maxAge != null) {
hstsMaxAgeString = hsts.maxAge.toString()
}
return {
policy: policy,
@@ -60,6 +64,7 @@ Vue.component("ssl-config-box", {
hsts: hsts,
hstsOptionsVisible: false,
hstsDomainAdding: false,
hstsMaxAgeString: hstsMaxAgeString,
addingHstsDomain: "",
hstsDomainEditingIndex: -1,
@@ -233,22 +238,22 @@ Vue.component("ssl-config-box", {
// 监控HSTS有效期修改
changeHSTSMaxAge: function () {
var v = this.hsts.maxAge
if (isNaN(v)) {
var v = parseInt(this.hstsMaxAgeString)
if (isNaN(v) || v < 0) {
this.hsts.maxAge = 0
this.hsts.days = "-"
return
}
this.hsts.days = parseInt(v / 86400)
if (isNaN(this.hsts.days)) {
this.hsts.days = "-"
} else if (this.hsts.days < 0) {
this.hsts.maxAge = v
this.hsts.days = v / 86400
if (this.hsts.days == 0) {
this.hsts.days = "-"
}
},
// 设置HSTS有效期
setHSTSMaxAge: function (maxAge) {
this.hsts.maxAge = maxAge
this.hstsMaxAgeString = maxAge.toString()
this.changeHSTSMaxAge()
},
@@ -441,7 +446,7 @@ Vue.component("ssl-config-box", {
<td>
<div class="ui fields inline">
<div class="ui field">
<input type="text" name="hstsMaxAge" v-model="hsts.maxAge" maxlength="10" size="10" @input="changeHSTSMaxAge()"/>
<input type="text" name="hstsMaxAge" v-model="hstsMaxAgeString" maxlength="10" size="10" @input="changeHSTSMaxAge()"/>
</div>
<div class="ui field">

View File

@@ -63,7 +63,7 @@ Vue.component("traffic-limit-config-box", {
<table class="ui table selectable definition">
<tbody>
<tr>
<td class="title">是否启用</td>
<td class="title">启用流量限制</td>
<td>
<checkbox v-model="config.isOn"></checkbox>
<p class="comment">注意由于流量统计是每5分钟统计一次所以超出流量限制后对用户的提醒也会有所延迟。</p>

View File

@@ -0,0 +1,142 @@
Vue.component("user-agent-config-box", {
props: ["v-is-location", "v-is-group", "value"],
data: function () {
let config = this.value
if (config == null) {
config = {
isPrior: false,
isOn: false,
filters: []
}
}
if (config.filters == null) {
config.filters = []
}
return {
config: config,
isAdding: false,
addingFilter: {
keywords: [],
action: "deny"
}
}
},
methods: {
isOn: function () {
return ((!this.vIsLocation && !this.vIsGroup) || this.config.isPrior) && this.config.isOn
},
remove: function (index) {
let that = this
teaweb.confirm("确定要删除此名单吗?", function () {
that.config.filters.$remove(index)
})
},
add: function () {
this.isAdding = true
},
confirm: function () {
if (this.addingFilter.action == "deny") {
this.config.filters.push(this.addingFilter)
} else {
let index = -1
this.config.filters.forEach(function (filter, filterIndex) {
if (filter.action == "allow") {
index = filterIndex
}
})
if (index < 0) {
this.config.filters.unshift(this.addingFilter)
} else {
this.config.filters.$insert(index + 1, this.addingFilter)
}
}
this.cancel()
},
cancel: function () {
this.isAdding = false
this.addingFilter = {
keywords: [],
action: "deny"
}
},
changeKeywords: function (keywords) {
this.addingFilter.keywords = keywords
}
},
template: `<div>
<input type="hidden" name="userAgentJSON" :value="JSON.stringify(config)"/>
<table class="ui table definition selectable">
<prior-checkbox :v-config="config" v-if="vIsLocation || vIsGroup"></prior-checkbox>
<tbody v-show="(!vIsLocation && !vIsGroup) || config.isPrior">
<tr>
<td class="title">启用UA名单</td>
<td>
<div class="ui checkbox">
<input type="checkbox" value="1" v-model="config.isOn"/>
<label></label>
</div>
<p class="comment">选中后表示开启UserAgent名单。</p>
</td>
</tr>
</tbody>
<tbody v-show="isOn()">
<tr>
<td>UA名单</td>
<td>
<div v-if="config.filters.length > 0">
<table class="ui table celled">
<thead class="full-width">
<tr>
<th>UA关键词</th>
<th class="two wide">动作</th>
<th class="one op">操作</th>
</tr>
</thead>
<tbody v-for="(filter, index) in config.filters">
<tr>
<td style="background: white">
<span v-for="keyword in filter.keywords" class="ui label basic tiny">
<span v-if="keyword.length > 0">{{keyword}}</span>
<span v-if="keyword.length == 0" class="disabled">[空]</span>
</span>
</td>
<td>
<span v-if="filter.action == 'allow'" class="green">允许</span><span v-if="filter.action == 'deny'" class="red">不允许</span>
</td>
<td><a href="" @click.prevent="remove(index)">删除</a></td>
</tr>
</tbody>
</table>
</div>
<div v-if="isAdding" style="margin-top: 0.5em">
<table class="ui table definition">
<tr>
<td class="title">UA关键词</td>
<td>
<values-box :v-values="addingFilter.keywords" :v-allow-empty="true" @change="changeKeywords"></values-box>
<p class="comment">不区分大小写,比如<code-label>Chrome</code-label>;支持<code-label>*</code-label>通配符,比如<code-label>*Firefox*</code-label>也支持空的关键词表示空UserAgent。</p>
</td>
</tr>
<tr>
<td>动作</td>
<td><select class="ui dropdown auto-width" v-model="addingFilter.action">
<option value="deny">不允许</option>
<option value="allow">允许</option>
</select>
</td>
</tr>
</table>
<button type="button" class="ui button tiny" @click.prevent="confirm">保存</button> &nbsp; <a href="" @click.prevent="cancel" title="取消"><i class="icon remove small"></i></a>
</div>
<div v-show="!isAdding" style="margin-top: 0.5em">
<button class="ui button tiny" type="button" @click.prevent="add">+</button>
</div>
</td>
</tr>
</tbody>
</table>
<div class="margin"></div>
</div>`
})

View File

@@ -49,6 +49,10 @@ window.teaweb = {
}
return true;
},
clone: function (source) {
let s = JSON.stringify(source)
return JSON.parse(s)
},
loadJS: function (file, callback) {
let element = document.createElement("script")
@@ -349,6 +353,9 @@ window.teaweb = {
Swal: function () {
return this.isPopup() ? window.parent.Swal : window.Swal;
},
hasPopup: function () {
return document.getElementsByClassName("swal2-container").length > 0
},
success: function (message, callback) {
var width = "20em";
if (message.length > 30) {
@@ -940,7 +947,7 @@ window.teaweb = {
},
chartMap: {}, // dom id => chart
initChart: function (dom, cache) {
if (typeof(cache) != "boolean") {
if (typeof (cache) != "boolean") {
cache = true
}

View File

@@ -728,7 +728,7 @@ span.olive,
var.olive {
color: #b5cc18 !important;
}
var.dash {
span.dash {
border-bottom: 1px dashed grey;
}
var.normal {

File diff suppressed because one or more lines are too long

View File

@@ -118,6 +118,12 @@ Tea.context(function () {
return
}
this.$post("/clusters/tasks/check")
.params({
isDoing: this.doingNodeTasks.isDoing ? 1 : 0,
hasError: this.doingNodeTasks.hasError ? 1 : 0,
isUpdated: this.doingNodeTasks.isUpdated ? 1 : 0
})
.timeout(60)
.success(function (resp) {
this.doingNodeTasks.isDoing = resp.data.isDoing
this.doingNodeTasks.hasError = resp.data.hasError
@@ -151,6 +157,12 @@ Tea.context(function () {
return
}
this.$post("/dns/tasks/check")
.params({
isDoing: this.doingDNSTasks.isDoing ? 1 : 0,
hasError: this.doingDNSTasks.hasError ? 1 : 0,
isUpdated: this.doingDNSTasks.isUpdated ? 1 : 0
})
.timeout(60)
.success(function (resp) {
this.doingDNSTasks.isDoing = resp.data.isDoing
this.doingDNSTasks.hasError = resp.data.hasError

View File

@@ -748,7 +748,7 @@ span.olive, var.olive {
color: #b5cc18 !important;
}
var.dash {
span.dash {
border-bottom: 1px dashed grey;
}

View File

@@ -239,7 +239,7 @@ span.olive,
var.olive {
color: #b5cc18 !important;
}
var.dash {
span.dash {
border-bottom: 1px dashed grey;
}
/** Message **/
@@ -312,4 +312,17 @@ textarea.wide-code {
.combo-box .menu::-webkit-scrollbar {
width: 4px;
}
code-label {
background: #fff;
border: 1px solid rgba(34, 36, 38, 0.15);
color: rgba(0, 0, 0, 0.87);
font-size: 0.71428571rem;
padding: 3px;
margin-left: 2px;
margin-right: 2px;
line-height: 1;
display: inline-block;
font-weight: 700;
vertical-align: baseline;
}
/*# sourceMappingURL=@layout_popup.css.map */

View File

@@ -1 +1 @@
{"version":3,"sources":["@layout_popup.less"],"names":[],"mappings":"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","file":"@layout_popup.css"}
{"version":3,"sources":["@layout_popup.less"],"names":[],"mappings":"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","file":"@layout_popup.css"}

View File

@@ -292,7 +292,7 @@ span.olive, var.olive {
color: #b5cc18 !important;
}
var.dash {
span.dash {
border-bottom: 1px dashed grey;
}
@@ -379,4 +379,19 @@ textarea.wide-code {
.combo-box .menu::-webkit-scrollbar {
width: 4px;
}
// code-label
code-label {
background: #fff;
border: 1px solid rgba(34, 36, 38, .15);
color: rgba(0, 0, 0, .87);
font-size: .71428571rem;
padding: 3px;
margin-left: 2px;
margin-right: 2px;
line-height: 1;
display: inline-block;
font-weight: 700;
vertical-align: baseline;
}

View File

@@ -64,7 +64,7 @@
</td>
</tr>
<tr>
<td>是否启用</td>
<td>启用当前管理员</td>
<td>
<checkbox name="isOn" v-model="admin.isOn"></checkbox>
</td>

View File

@@ -256,7 +256,7 @@
<td>上次更新时间</td>
<td>
{{nodeDatetime}}
<p class="comment" v-if="nodeTimeDiff > 3"><span class="red">当前节点时间与API节点时间相差 {{nodeTimeDiff}} 秒,请同步节点时间。</span></p>
<p class="comment" v-if="nodeTimeDiff > 30"><span class="red">当前节点时间与API节点时间相差 {{nodeTimeDiff}} 秒,请同步节点时间。</span></p>
</td>
</tr>
</tbody>

View File

@@ -6,7 +6,7 @@
<div>
<second-menu>
<menu-item @click.prevent="createThreshold">添加阈值</menu-item>
<menu-item @click.prevent="createThreshold">[添加阈值]</menu-item>
</second-menu>
</div>

View File

@@ -9,11 +9,16 @@
<csrf-token></csrf-token>
<table class="ui table selectable definition">
<tr v-if="hasDomains">
<tr>
<td>选择主域名 *</td>
<td>
<dns-domain-selector :v-domain-id="domainId" :v-domain-name="domainName" :v-provider-name="domainProvider.name" @change="changeDomain"></dns-domain-selector>
<p class="comment">用于生成集群节点和网站服务的DNS解析记录<span v-if="domainId > 0">,修改后将自动删除旧域名中的相关记录</span></p>
<div v-if="hasDomains">
<dns-domain-selector :v-domain-id="domainId" :v-domain-name="domainName" :v-provider-name="domainProvider.name" @change="changeDomain"></dns-domain-selector>
<p class="comment">用于生成集群节点和网站服务的DNS解析记录<span v-if="domainId > 0">,修改后将自动删除旧域名中的相关记录</span></p>
</div>
<div v-else>
没有可用的域名,请在 <a href="/dns/providers" target="_blank">[域名解析]</a> 中添加。
</div>
</td>
</tr>
<tr v-if="oldDomain.id > 0 && domain.id == 0">

View File

@@ -35,7 +35,7 @@
<td class="color-border">允许使用节点IP访问</td>
<td>
<checkbox name="httpAllAllowNodeIP" v-model="config.httpAll.allowNodeIP"></checkbox>
<p class="comment">选中后表示允许使用节点IP访问网站。</p>
<p class="comment">选中后,表示允许直接使用节点IP访问网站。</p>
</td>
</tr>
<tr v-show="config.httpAll.matchDomainStrictly">
@@ -90,6 +90,31 @@
</tr>
</table>
<h4>性能</h4>
<table class="ui table definition selectable">
<tr>
<td class="title">自动读数据超时</td>
<td>
<checkbox name="performanceAutoReadTimeout" v-model="config.performance.autoReadTimeout"></checkbox>
<p class="comment">从客户端读取数据时自动设置超时时间,如果超时,则自动视为慢连接,并关闭网络连接;此为专业选项,请在专家指导下进行修改。</p>
</td>
</tr>
<tr>
<td class="title">自动写数据超时</td>
<td>
<checkbox name="performanceAutoWriteTimeout" v-model="config.performance.autoWriteTimeout"></checkbox>
<p class="comment">向客户端发送数据时自动设置超时时间,如果超时,则自动视为慢连接,并关闭网络连接;此为专业选项,请在专家指导下进行修改。</p>
</td>
</tr>
<tr>
<td>调试模式</td>
<td>
<checkbox name="performanceDebug" v-model="config.performance.debug"></checkbox>
<p class="comment">开启调试模式后,将在某些信息中包含调试信息。</p>
</td>
</tr>
</table>
<submit-btn></submit-btn>
</form>
</div>

View File

@@ -10,6 +10,12 @@
<td class="title">集群名称 *</td>
<td><input type="text" name="name" maxlength="50" ref="focus" v-model="cluster.name"/></td>
</tr>
<tr v-if="cluster.domainName.length > 0">
<td>域名</td>
<td>
{{cluster.domainName}}<link-icon :href="'/clusters/cluster/settings/dns?clusterId=' + cluster.id"></link-icon>
</td>
</tr>
<tr>
<td>默认SSH认证</td>
<td>

View File

@@ -21,6 +21,7 @@ Tea.context(function () {
that.itemDescription = v.description
that.itemParams = v.params
that.threshold.param = v.params[0].code
that.paramDescription = v.params[0].description
}
})
}

View File

@@ -4,7 +4,7 @@
<div class="right-box with-menu">
<first-menu>
<menu-item @click.prevent="createThreshold">添加阈值</menu-item>
<menu-item @click.prevent="createThreshold">[添加阈值]</menu-item>
</first-menu>
<p class="comment" v-if="thresholds.length == 0">暂时还没有设置阈值。</p>

View File

@@ -26,6 +26,7 @@ Tea.context(function () {
that.itemDescription = v.description
that.itemParams = v.params
that.threshold.param = v.params[0].code
that.paramDescription = v.params[0].description
}
})
}

View File

@@ -93,6 +93,13 @@
<p class="comment">登录华为云控制台 -- 在"我的凭证 -- 访问密钥"中创建和获取。</p>
</td>
</tr>
<tr>
<td>终端节点</td>
<td>
<input type="text" name="paramHuaweiEndpoint" maxlength="100"/>
<p class="comment">选填项。可以填写终端节点Endpoint区域代号或者域名参考 <a href="https://developer.huaweicloud.com/endpoint?DNS" target="_blank">https://developer.huaweicloud.com/endpoint?DNS</a>(如果此链接失效,请到华为云开发者中心自行查找)。</p>
</td>
</tr>
</tbody>
<!-- CloudFlare -->

View File

@@ -67,6 +67,13 @@
<td>AccessKeySecret</td>
<td>{{provider.apiParams.accessKeySecret}}</td>
</tr>
<tr>
<td>终端节点</td>
<td>
<span v-if="provider.apiParams.endpoint != null && provider.apiParams.endpoint.length > 0">{{provider.apiParams.endpoint}}</span>
<span v-else class="disabled">默认</span>
</td>
</tr>
</tbody>
<!-- CloudFlare -->

View File

@@ -92,6 +92,13 @@
<p class="comment">登录华为云控制台 -- 在"我的凭证 -- 访问密钥"中创建和获取。</p>
</td>
</tr>
<tr>
<td>终端节点</td>
<td>
<input type="text" name="paramHuaweiEndpoint" maxlength="100" v-model="provider.params.endpoint"/>
<p class="comment">选填项。可以填写终端节点Endpoint区域代号或者域名参考 <a href="https://developer.huaweicloud.com/endpoint?DNS" target="_blank">https://developer.huaweicloud.com/endpoint?DNS</a>(如果此链接失效,请到华为云开发者中心自行查找)。</p>
</td>
</tr>
</tbody>

View File

@@ -1,6 +1,9 @@
{$layout}
{$template "menu"}
<div class="margin"></div>
<div><span class="grey">预热缓存指的是预先从源站读取最新内容当用户访问预热后的URL时直接从缓存中返回内容不需要再次回源。</span></div>
<form method="post" class="ui form" data-tea-action="$" data-tea-before="before" data-tea-success="success" data-tea-fail="fail" data-tea-done="done" data-tea-timeout="3600">
<csrf-token></csrf-token>
<table class="ui table definition selectable">

View File

@@ -3,6 +3,8 @@
<div class="margin"></div>
<div><span class="grey">刷新缓存指的是标记URL列表或目录为失效状态当有新的用户请求这些URL时会再次从源站读取最新的内容。</span></div>
<form method="post" class="ui form" data-tea-action="$" data-tea-before="before" data-tea-success="success" data-tea-fail="fail" data-tea-done="done" data-tea-timeout="300">
<csrf-token></csrf-token>
<table class="ui table definition selectable">

View File

@@ -27,7 +27,7 @@ Tea.context(function () {
this.rule.checkpointPrefix = param
}
this.$delay(function () {
this.changeCheckpoint()
this.loadCheckpoint()
if (this.rule.checkpointOptions != null && this.checkpoint != null && this.checkpoint.options != null) {
let that = this
this.checkpoint.options.forEach(function (option) {
@@ -43,6 +43,18 @@ Tea.context(function () {
* checkpoint
*/
this.checkpoint = null
this.loadCheckpoint = function () {
if (this.rule.checkpointPrefix.length == 0) {
this.checkpoint = null
return
}
let that = this
this.checkpoint = this.checkpoints.$find(function (k, v) {
return v.prefix == that.rule.checkpointPrefix
})
}
this.changeCheckpoint = function () {
if (this.rule.checkpointPrefix.length == 0) {
this.checkpoint = null

View File

@@ -6,7 +6,7 @@
<input type="hidden" name="firewallPolicyId" :value="firewallPolicyId"/>
<table class="ui table definition selectable">
<tr>
<td class="title">选择要入的规则文件</td>
<td class="title">选择要入的规则文件</td>
<td>
<input type="file" name="file" accept=".json"/>
</td>

View File

@@ -57,7 +57,6 @@ Tea.context(function () {
// 添加分组
this.createGroup = function (type) {
teaweb.popup("/servers/components/waf/createGroupPopup?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type, {
height: "16em",
callback: function () {
teaweb.success("保存成功", function () {
window.location.reload()

View File

@@ -8,6 +8,14 @@ Tea.context(function () {
this.isLoaded = false
this.load = function () {
// 如果有弹窗时,暂时不更新
if (teaweb.hasPopup()) {
this.$delay(function () {
this.load()
}, 5000)
return
}
this.$post("$")
.params({
serverId: this.serverId,

View File

@@ -0,0 +1,9 @@
{$layout "layout_popup"}
<h3>CORS跨域设置</h3>
<form class="ui form" data-tea-action="$" data-tea-success="success">
<csrf-token></csrf-token>
<input type="hidden" name="headerPolicyId" :value="headerPolicyId"/>
<http-cors-header-config-box v-model="cors"></http-cors-header-config-box>
<submit-btn></submit-btn>
</form>

View File

@@ -10,7 +10,15 @@
<td>所属用户</td>
<td>
<span v-if="user != null">{{user.fullname}} <span class="small">{{user.username}}</span><link-icon :href="'/users/user?userId=' + user.id"></link-icon></span>
<span v-else class="disabled">-</span>
<div v-if="user == null">
<div v-show="!userSelectorVisible">
<span class="disabled">没有指定用户</span> &nbsp; <a href="" @click.prevent="showUserSelector">[指定用户]</a>
</div>
<div v-show="userSelectorVisible">
<user-selector style="display:inline-block"></user-selector>
<p class="comment"><span class="red">此操作同时会将与当前服务相关联的证书等数据自动修改为此用户所属。</span></p>
</div>
</div>
</td>
</tr>
<tr>
@@ -66,7 +74,7 @@
</td>
</tr>
<tr>
<td>是否启用</td>
<td>启用当前服务</td>
<td>
<div class="ui checkbox">
<input type="checkbox" name="isOn" value="1" v-model="server.isOn"/>

View File

@@ -4,6 +4,12 @@ Tea.context(function () {
/**
* 用户相关
*/
this.userSelectorVisible = false
this.showUserSelector = function () {
this.userSelectorVisible = !this.userSelectorVisible
}
this.userId = 0
this.plans = []
this.userPlanId = 0

View File

@@ -0,0 +1,18 @@
{$layout}
{$template "/left_menu"}
<div class="right-box">
{$template "../location_menu"}
{$template "../left_menu"}
<div class="right-box tiny">
<form class="ui form" data-tea-action="$" data-tea-success="success">
<csrf-token></csrf-token>
<input type="hidden" name="webId" :value="webId"/>
<user-agent-config-box v-model="userAgentConfig" :v-is-location="true"></user-agent-config-box>
<submit-btn></submit-btn>
</form>
</div>
</div>

View File

@@ -0,0 +1,3 @@
Tea.context(function () {
this.success = NotifyReloadSuccess("保存成功")
})

View File

@@ -0,0 +1,13 @@
{$layout}
{$template "../settings_menu"}
{$template "/left_menu_with_menu"}
<div class="right-box with-menu">
<form class="ui form" data-tea-action="$" data-tea-success="success">
<csrf-token></csrf-token>
<input type="hidden" name="webId" :value="webId"/>
<user-agent-config-box v-model="userAgentConfig"></user-agent-config-box>
<submit-btn></submit-btn>
</form>
</div>

View File

@@ -0,0 +1,3 @@
Tea.context(function () {
this.success = NotifyReloadSuccess("保存成功")
})

View File

@@ -57,7 +57,6 @@ Tea.context(function () {
// 添加分组
this.createGroup = function (type) {
teaweb.popup("/servers/components/waf/createGroupPopup?firewallPolicyId=" + this.firewallPolicyId + "&type=" + type, {
height: "16em",
callback: function () {
teaweb.success("保存成功", function () {
window.location.reload()

View File

@@ -33,35 +33,42 @@
<td>关联集群</td>
<td>
<span v-if="user.cluster != null">{{user.cluster.name}} <link-icon :href="'/clusters/cluster?clusterId=' + user.cluster.id"></link-icon></span>
<span v-else class="disabled">-</span>
<span v-else class="disabled">没有设置。</span>
</td>
</tr>
<tr>
<td>手机号</td>
<td>
<span v-if="user.mobile.length > 0">{{user.mobile}}</span>
<span v-else class="disabled">-</span>
<span v-else class="disabled">没有设置。</span>
</td>
</tr>
<tr>
<td>联系电话</td>
<td>
<span v-if="user.tel.length > 0">{{user.tel}}</span>
<span v-else class="disabled">-</span>
<span v-else class="disabled">没有设置。</span>
</td>
</tr>
<tr>
<td>电子邮箱</td>
<td>常用电子邮箱</td>
<td>
<span v-if="user.email.length > 0">{{user.email}}</span>
<span v-else class="disabled">-</span>
<span v-else class="disabled">没有设置。</span>
</td>
</tr>
<tr>
<td>已绑定电子邮箱</td>
<td>
<span v-if="user.verifiedEmail.length > 0">{{user.verifiedEmail}}</span>
<span v-else class="disabled">没有设置。</span>
</td>
</tr>
<tr>
<td>备注</td>
<td>
<span v-if="user.remark.length > 0">{{user.remark}}</span>
<span v-else class="disabled">-</span>
<span v-else class="disabled">没有设置。</span>
</td>
</tr>
<tr>