Compare commits
109 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d02e3f15a | ||
|
|
bf82f22d0f | ||
|
|
e18f182ce6 | ||
|
|
761c26b587 | ||
|
|
5e62769dcf | ||
|
|
86b8a718a0 | ||
|
|
a729cfc31d | ||
|
|
96cfda852a | ||
|
|
0423d9246c | ||
|
|
985798757f | ||
|
|
72876f6749 | ||
|
|
03d6e223d8 | ||
|
|
62d9f2ed97 | ||
|
|
a550a44a52 | ||
|
|
b19d586949 | ||
|
|
bbfa3ee57f | ||
|
|
af409dd3b8 | ||
|
|
3db79ca149 | ||
|
|
e880420494 | ||
|
|
28ec17b8fe | ||
|
|
8026a40807 | ||
|
|
068c6d406a | ||
|
|
57470e4ef0 | ||
|
|
ca8e1537f5 | ||
|
|
d67b818398 | ||
|
|
f5f46424bb | ||
|
|
1e259717ce | ||
|
|
91ece99a9c | ||
|
|
d30ebdb369 | ||
|
|
ade8522b69 | ||
|
|
159b308f31 | ||
|
|
837bf25f7b | ||
|
|
8301d3669b | ||
|
|
cc752e8d80 | ||
|
|
d20e6bd42f | ||
|
|
bfee9fe233 | ||
|
|
9c962b09f1 | ||
|
|
46edefead7 | ||
|
|
725cfc8a2b | ||
|
|
1ce48b9ef4 | ||
|
|
37cc28f225 | ||
|
|
5ebe3bb8e0 | ||
|
|
aa01512f89 | ||
|
|
37ff2b886a | ||
|
|
ce18212756 | ||
|
|
08f50a274a | ||
|
|
892ee0013a | ||
|
|
e9a47041fd | ||
|
|
d419fa06e8 | ||
|
|
8b961a890c | ||
|
|
db32915114 | ||
|
|
2ffdb10cce | ||
|
|
507fd7e5d4 | ||
|
|
7df599b5a9 | ||
|
|
9987334f55 | ||
|
|
d8c3365384 | ||
|
|
2e284b5af9 | ||
|
|
89ddd4e6a3 | ||
|
|
36524ea481 | ||
|
|
35cf693610 | ||
|
|
42148a66bd | ||
|
|
96878715bf | ||
|
|
1a5f3342e7 | ||
|
|
3613d13a2b | ||
|
|
7786140d85 | ||
|
|
3a23b57f1b | ||
|
|
5a6e6fba69 | ||
|
|
910b3a6162 | ||
|
|
0dc19bed45 | ||
|
|
a7bdb64301 | ||
|
|
4739072a85 | ||
|
|
07bdae2488 | ||
|
|
b84035d821 | ||
|
|
dc0a7b9dae | ||
|
|
2937bd8de0 | ||
|
|
37315ef4d9 | ||
|
|
1986fece07 | ||
|
|
16b1657f35 | ||
|
|
c115c62cd9 | ||
|
|
d2df7f8d5b | ||
|
|
6cb79864e6 | ||
|
|
982d28c7b4 | ||
|
|
0f57516fdc | ||
|
|
75a89defcb | ||
|
|
22a6c52060 | ||
|
|
37607e4a41 | ||
|
|
5936155998 | ||
|
|
8d76de935f | ||
|
|
9baa530064 | ||
|
|
103414b338 | ||
|
|
72fe68ebfe | ||
|
|
cfed31958b | ||
|
|
3d5fca2d36 | ||
|
|
a5710286ec | ||
|
|
d0ce0c6c58 | ||
|
|
779e2cf0f2 | ||
|
|
2108474777 | ||
|
|
e25e0f1747 | ||
|
|
e8e74b639c | ||
|
|
a14fcd1e50 | ||
|
|
485c0e0891 | ||
|
|
00a19e9d43 | ||
|
|
67d0dc0783 | ||
|
|
3718c35842 | ||
|
|
567ffc80b6 | ||
|
|
5d15a08ac8 | ||
|
|
2b84037346 | ||
|
|
536f11e617 | ||
|
|
5d367a384e |
1
docker/.gitignore
vendored
Normal file
1
docker/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.zip
|
||||
37
docker/Dockerfile
Normal file
37
docker/Dockerfile
Normal file
@@ -0,0 +1,37 @@
|
||||
FROM alpine:latest
|
||||
LABEL maintainer="iwind.liu@gmail.com"
|
||||
ENV TZ "Asia/Shanghai"
|
||||
ENV VERSION 0.6.2
|
||||
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
|
||||
|
||||
RUN apk add wget
|
||||
RUN mkdir ${ROOT_DIR}; \
|
||||
cd ${ROOT_DIR}; \
|
||||
wget ${TAR_URL} -O ${TAR_FILE}; \
|
||||
apk add unzip; \
|
||||
unzip ${TAR_FILE}; \
|
||||
rm -f ${TAR_FILE}
|
||||
|
||||
RUN apk add mysql mysql-client; \
|
||||
sed -e "s/\[mysqld\]/\[mysqld\]\n\ndatadir=\/var\/lib\/mysql\nport=3306\ninnodb_flush_log_at_trx_commit=2\nmax_connections=256\nmax_prepared_stmt_count=65535\nbinlog_cache_size=1M\nbinlog_stmt_cache_size=1M\nthread_cache_size=32\nbinlog_expire_logs_seconds=1209600\n\n/" /etc/my.cnf > /tmp/my.cnf; \
|
||||
cp /tmp/my.cnf /etc/my.cnf; \
|
||||
sed -e "s/skip-networking/#skip-networking/" /etc/my.cnf.d/mariadb-server.cnf > /tmp/mariadb-server.cnf; \
|
||||
cp /tmp/mariadb-server.cnf /etc/my.cnf.d/mariadb-server.cnf; \
|
||||
mysql_install_db --user=mysql
|
||||
RUN mysqld_safe --user=mysql & \
|
||||
sleep 5; \
|
||||
mysql -uroot -hlocalhost --execute="ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';"
|
||||
|
||||
RUN echo -e "#!/usr/bin/env sh\n\nmysqld_safe --user=mysql &\n/usr/local/goedge/edge-admin/bin/edge-admin\n" > ${ROOT_DIR}/run.sh; \
|
||||
chmod u+x ${ROOT_DIR}/run.sh
|
||||
|
||||
EXPOSE 7788
|
||||
EXPOSE 8001
|
||||
EXPOSE 3306
|
||||
|
||||
ENTRYPOINT [ "/usr/local/goedge/run.sh" ]
|
||||
5
docker/build.sh
Executable file
5
docker/build.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
VERSION=latest
|
||||
|
||||
docker build --no-cache -t goedge/edge-admin:${VERSION} .
|
||||
5
docker/run.sh
Executable file
5
docker/run.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
VERSION=latest
|
||||
|
||||
docker run -d -p 7788:7788 -p 8001:8001 -p 3306:3306 --name edge-admin goedge/edge-admin:${VERSION}
|
||||
8
go.mod
8
go.mod
@@ -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
20
go.sum
@@ -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=
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
package configloaders
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var sharedUserUIConfig *systemconfigs.UserUIConfig = nil
|
||||
|
||||
const (
|
||||
UserUISettingName = "userUIConfig"
|
||||
)
|
||||
|
||||
func LoadUserUIConfig() (*systemconfigs.UserUIConfig, error) {
|
||||
locker.Lock()
|
||||
defer locker.Unlock()
|
||||
|
||||
config, err := loadUserUIConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := reflect.Indirect(reflect.ValueOf(config)).Interface().(systemconfigs.UserUIConfig)
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
func UpdateUserUIConfig(uiConfig *systemconfigs.UserUIConfig) error {
|
||||
locker.Lock()
|
||||
defer locker.Unlock()
|
||||
|
||||
var rpcClient, err = rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
valueJSON, err := json.Marshal(uiConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = rpcClient.SysSettingRPC().UpdateSysSetting(rpcClient.Context(0), &pb.UpdateSysSettingRequest{
|
||||
Code: UserUISettingName,
|
||||
ValueJSON: valueJSON,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sharedUserUIConfig = uiConfig
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadUserUIConfig() (*systemconfigs.UserUIConfig, error) {
|
||||
if sharedUserUIConfig != nil {
|
||||
return sharedUserUIConfig, nil
|
||||
}
|
||||
var rpcClient, err = rpc.SharedRPC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := rpcClient.SysSettingRPC().ReadSysSetting(rpcClient.Context(0), &pb.ReadSysSettingRequest{
|
||||
Code: UserUISettingName,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(resp.ValueJSON) == 0 {
|
||||
sharedUserUIConfig = defaultUserUIConfig()
|
||||
return sharedUserUIConfig, nil
|
||||
}
|
||||
|
||||
config := &systemconfigs.UserUIConfig{}
|
||||
err = json.Unmarshal(resp.ValueJSON, config)
|
||||
if err != nil {
|
||||
logs.Println("[UI_MANAGER]" + err.Error())
|
||||
sharedUserUIConfig = defaultUserUIConfig()
|
||||
return sharedUserUIConfig, nil
|
||||
}
|
||||
sharedUserUIConfig = config
|
||||
return sharedUserUIConfig, nil
|
||||
}
|
||||
|
||||
func defaultUserUIConfig() *systemconfigs.UserUIConfig {
|
||||
return &systemconfigs.UserUIConfig{
|
||||
ProductName: "GoEdge",
|
||||
UserSystemName: "GoEdge用户系统",
|
||||
ShowOpenSourceInfo: true,
|
||||
ShowVersion: true,
|
||||
ShowFinance: true,
|
||||
BandwidthUnit: systemconfigs.BandwidthUnitBit,
|
||||
ShowBandwidthCharts: true,
|
||||
ShowTrafficCharts: true,
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "0.5.6"
|
||||
Version = "0.6.3"
|
||||
|
||||
APINodeVersion = "0.5.6"
|
||||
APINodeVersion = "0.6.3"
|
||||
|
||||
ProductName = "Edge Admin"
|
||||
ProcessName = "edge-admin"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -571,41 +571,30 @@ func (this *RPCClient) pickConn() *grpc.ClientConn {
|
||||
defer this.locker.Unlock()
|
||||
|
||||
// 检查连接状态
|
||||
if len(this.conns) > 0 {
|
||||
var availableConns = []*grpc.ClientConn{}
|
||||
for _, state := range []connectivity.State{connectivity.Ready, connectivity.Idle, connectivity.Connecting} {
|
||||
var countConns = len(this.conns)
|
||||
if countConns > 0 {
|
||||
if countConns == 1 {
|
||||
return this.conns[0]
|
||||
}
|
||||
for _, state := range []connectivity.State{
|
||||
connectivity.Ready,
|
||||
connectivity.Idle,
|
||||
connectivity.Connecting,
|
||||
connectivity.TransientFailure,
|
||||
} {
|
||||
var availableConns = []*grpc.ClientConn{}
|
||||
for _, conn := range this.conns {
|
||||
if conn.GetState() == state {
|
||||
availableConns = append(availableConns, conn)
|
||||
}
|
||||
}
|
||||
if len(availableConns) > 0 {
|
||||
break
|
||||
return this.randConn(availableConns)
|
||||
}
|
||||
}
|
||||
|
||||
if len(availableConns) > 0 {
|
||||
return availableConns[rands.Int(0, len(availableConns)-1)]
|
||||
}
|
||||
|
||||
// 关闭
|
||||
for _, conn := range this.conns {
|
||||
_ = conn.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// 重新初始化
|
||||
err := this.init()
|
||||
if err != nil {
|
||||
// 错误提示已经在构造对象时打印过,所以这里不再重复打印
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(this.conns) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return this.conns[rands.Int(0, len(this.conns)-1)]
|
||||
return this.randConn(this.conns)
|
||||
}
|
||||
|
||||
// Close 关闭
|
||||
@@ -639,3 +628,14 @@ func (this *RPCClient) localIPAddrs() []string {
|
||||
}
|
||||
return localIPAddrs
|
||||
}
|
||||
|
||||
func (this *RPCClient) randConn(conns []*grpc.ClientConn) *grpc.ClientConn {
|
||||
var l = len(conns)
|
||||
if l == 0 {
|
||||
return nil
|
||||
}
|
||||
if l == 1 {
|
||||
return conns[0]
|
||||
}
|
||||
return conns[rands.Int(0, l-1)]
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
55
internal/utils/time.go
Normal file
55
internal/utils/time.go
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// RangeTimes 计算时间点
|
||||
func RangeTimes(timeFrom string, timeTo string, everyMinutes int32) (result []string, err error) {
|
||||
if everyMinutes <= 0 {
|
||||
return nil, errors.New("invalid 'everyMinutes'")
|
||||
}
|
||||
|
||||
var reg = regexp.MustCompile(`^\d{4}$`)
|
||||
if !reg.MatchString(timeFrom) {
|
||||
return nil, errors.New("invalid timeFrom '" + timeFrom + "'")
|
||||
}
|
||||
if !reg.MatchString(timeTo) {
|
||||
return nil, errors.New("invalid timeTo '" + timeTo + "'")
|
||||
}
|
||||
|
||||
if timeFrom > timeTo {
|
||||
// swap
|
||||
timeFrom, timeTo = timeTo, timeFrom
|
||||
}
|
||||
|
||||
var everyMinutesInt = int(everyMinutes)
|
||||
|
||||
var fromHour = types.Int(timeFrom[:2])
|
||||
var fromMinute = types.Int(timeFrom[2:])
|
||||
var toHour = types.Int(timeTo[:2])
|
||||
var toMinute = types.Int(timeTo[2:])
|
||||
|
||||
if fromMinute%everyMinutesInt == 0 {
|
||||
result = append(result, timeFrom)
|
||||
}
|
||||
|
||||
for {
|
||||
fromMinute += everyMinutesInt
|
||||
if fromMinute > 59 {
|
||||
fromHour += fromMinute / 60
|
||||
fromMinute = fromMinute % 60
|
||||
}
|
||||
if fromHour > toHour || (fromHour == toHour && fromMinute > toMinute) {
|
||||
break
|
||||
}
|
||||
result = append(result, fmt.Sprintf("%02d%02d", fromHour, fromMinute))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -49,7 +49,11 @@ func (this *ParentAction) ErrorText(err string) {
|
||||
}
|
||||
|
||||
func (this *ParentAction) NotFound(name string, itemId int64) {
|
||||
this.ErrorPage(errors.New(name + " id: '" + strconv.FormatInt(itemId, 10) + "' is not found"))
|
||||
if itemId > 0 {
|
||||
this.ErrorPage(errors.New(name + " id: '" + strconv.FormatInt(itemId, 10) + "' is not found"))
|
||||
} else {
|
||||
this.ErrorPage(errors.New(name + " is not found"))
|
||||
}
|
||||
}
|
||||
|
||||
func (this *ParentAction) NewPage(total int64, size ...int64) *Page {
|
||||
@@ -126,11 +130,8 @@ func (this *ParentAction) RPC() *rpc.RPCClient {
|
||||
}
|
||||
|
||||
// AdminContext 获取Context
|
||||
// 每个请求的context都必须是一个新的实例
|
||||
func (this *ParentAction) AdminContext() context.Context {
|
||||
if this.ctx != nil {
|
||||
return this.ctx
|
||||
}
|
||||
|
||||
if this.rpcClient == nil {
|
||||
rpcClient, err := rpc.SharedRPC()
|
||||
if err != nil {
|
||||
|
||||
@@ -22,7 +22,7 @@ func init() {
|
||||
Post("/options", new(OptionsAction)).
|
||||
|
||||
// AccessKeys
|
||||
Prefix("/admins/accessKeys").
|
||||
Prefix("/admins/accesskeys").
|
||||
Get("", new(accesskeys.IndexAction)).
|
||||
GetPost("/createPopup", new(accesskeys.CreatePopupAction)).
|
||||
Post("/delete", new(accesskeys.DeleteAction)).
|
||||
|
||||
@@ -4,10 +4,12 @@ import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
)
|
||||
|
||||
type CreatePopupAction struct {
|
||||
@@ -40,11 +42,11 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
Field("name", params.Name).
|
||||
Require("请输入API节点名称")
|
||||
|
||||
httpConfig := &serverconfigs.HTTPProtocolConfig{}
|
||||
httpsConfig := &serverconfigs.HTTPSProtocolConfig{}
|
||||
var httpConfig = &serverconfigs.HTTPProtocolConfig{}
|
||||
var httpsConfig = &serverconfigs.HTTPSProtocolConfig{}
|
||||
|
||||
// 监听地址
|
||||
listens := []*serverconfigs.NetworkAddressConfig{}
|
||||
var listens = []*serverconfigs.NetworkAddressConfig{}
|
||||
err := json.Unmarshal(params.ListensJSON, &listens)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
@@ -64,15 +66,19 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
}
|
||||
|
||||
// Rest监听地址
|
||||
restHTTPConfig := &serverconfigs.HTTPProtocolConfig{}
|
||||
restHTTPSConfig := &serverconfigs.HTTPSProtocolConfig{}
|
||||
var restHTTPConfig = &serverconfigs.HTTPProtocolConfig{}
|
||||
var restHTTPSConfig = &serverconfigs.HTTPSProtocolConfig{}
|
||||
if params.RestIsOn {
|
||||
restListens := []*serverconfigs.NetworkAddressConfig{}
|
||||
var restListens = []*serverconfigs.NetworkAddressConfig{}
|
||||
err = json.Unmarshal(params.RestListensJSON, &restListens)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(restListens) == 0 {
|
||||
this.Fail("请至少添加一个HTTP API监听端口")
|
||||
return
|
||||
}
|
||||
for _, addr := range restListens {
|
||||
if addr.Protocol.IsHTTPFamily() {
|
||||
restHTTPConfig.IsOn = true
|
||||
@@ -82,10 +88,35 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
restHTTPSConfig.Listen = append(restHTTPSConfig.Listen, addr)
|
||||
}
|
||||
}
|
||||
|
||||
// 是否有端口冲突
|
||||
var rpcAddresses = []string{}
|
||||
for _, listen := range listens {
|
||||
err := listen.Init()
|
||||
if err != nil {
|
||||
this.Fail("校验配置失败:" + configutils.QuoteIP(listen.Host) + ":" + listen.PortRange + ": " + err.Error())
|
||||
return
|
||||
}
|
||||
rpcAddresses = append(rpcAddresses, listen.Addresses()...)
|
||||
}
|
||||
|
||||
for _, listen := range restListens {
|
||||
err := listen.Init()
|
||||
if err != nil {
|
||||
this.Fail("校验配置失败:" + configutils.QuoteIP(listen.Host) + ":" + listen.PortRange + ": " + err.Error())
|
||||
return
|
||||
}
|
||||
for _, address := range listen.Addresses() {
|
||||
if lists.ContainsString(rpcAddresses, address) {
|
||||
this.Fail("HTTP API地址 '" + address + "' 和 GRPC地址冲突,请修改后提交")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 证书
|
||||
certIds := []int64{}
|
||||
var certIds = []int64{}
|
||||
if len(params.CertIdsJSON) > 0 {
|
||||
err = json.Unmarshal(params.CertIdsJSON, &certIds)
|
||||
if err != nil {
|
||||
@@ -97,7 +128,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
this.Fail("请添加至少一个证书")
|
||||
}
|
||||
|
||||
certRefs := []*sslconfigs.SSLCertRef{}
|
||||
var certRefs = []*sslconfigs.SSLCertRef{}
|
||||
for _, certId := range certIds {
|
||||
certRefs = append(certRefs, &sslconfigs.SSLCertRef{
|
||||
IsOn: true,
|
||||
@@ -131,7 +162,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
}
|
||||
|
||||
// 访问地址
|
||||
accessAddrs := []*serverconfigs.NetworkAddressConfig{}
|
||||
var accessAddrs = []*serverconfigs.NetworkAddressConfig{}
|
||||
err = json.Unmarshal(params.AccessAddrsJSON, &accessAddrs)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -4,10 +4,12 @@ import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
@@ -175,12 +177,16 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
var restHTTPConfig = &serverconfigs.HTTPProtocolConfig{}
|
||||
var restHTTPSConfig = &serverconfigs.HTTPSProtocolConfig{}
|
||||
if params.RestIsOn {
|
||||
restListens := []*serverconfigs.NetworkAddressConfig{}
|
||||
var restListens = []*serverconfigs.NetworkAddressConfig{}
|
||||
err = json.Unmarshal(params.RestListensJSON, &restListens)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if len(restListens) == 0 {
|
||||
this.Fail("请至少添加一个HTTP API监听端口")
|
||||
return
|
||||
}
|
||||
for _, addr := range restListens {
|
||||
if addr.Protocol.IsHTTPFamily() {
|
||||
restHTTPConfig.IsOn = true
|
||||
@@ -190,6 +196,31 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
restHTTPSConfig.Listen = append(restHTTPSConfig.Listen, addr)
|
||||
}
|
||||
}
|
||||
|
||||
// 是否有端口冲突
|
||||
var rpcAddresses = []string{}
|
||||
for _, listen := range listens {
|
||||
err := listen.Init()
|
||||
if err != nil {
|
||||
this.Fail("校验配置失败:" + configutils.QuoteIP(listen.Host) + ":" + listen.PortRange + ": " + err.Error())
|
||||
return
|
||||
}
|
||||
rpcAddresses = append(rpcAddresses, listen.Addresses()...)
|
||||
}
|
||||
|
||||
for _, listen := range restListens {
|
||||
err := listen.Init()
|
||||
if err != nil {
|
||||
this.Fail("校验配置失败:" + configutils.QuoteIP(listen.Host) + ":" + listen.PortRange + ": " + err.Error())
|
||||
return
|
||||
}
|
||||
for _, address := range listen.Addresses() {
|
||||
if lists.ContainsString(rpcAddresses, address) {
|
||||
this.Fail("HTTP API地址 '" + address + "' 和 GRPC地址冲突,请修改后提交")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 证书
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/nodes/ipAddresses/ipaddressutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
@@ -300,6 +301,22 @@ func (this *DetailAction) RunGet(params struct {
|
||||
lnAddrs = []string{}
|
||||
}
|
||||
|
||||
// API节点地址
|
||||
var apiNodeAddrStrings = []string{}
|
||||
var apiNodeAddrs = []*serverconfigs.NetworkAddressConfig{}
|
||||
if len(node.ApiNodeAddrsJSON) > 0 {
|
||||
err = json.Unmarshal(node.ApiNodeAddrsJSON, &apiNodeAddrs)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, addr := range apiNodeAddrs {
|
||||
if addr.Init() == nil {
|
||||
apiNodeAddrStrings = append(apiNodeAddrStrings, addr.FullAddresses()...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
@@ -319,6 +336,7 @@ func (this *DetailAction) RunGet(params struct {
|
||||
"levelInfo": nodeconfigs.FindNodeLevel(int(node.Level)),
|
||||
"lnAddrs": lnAddrs,
|
||||
"enableIPLists": node.EnableIPLists,
|
||||
"apiNodeAddrs": apiNodeAddrStrings,
|
||||
|
||||
"status": maps.Map{
|
||||
"isActive": status.IsActive,
|
||||
@@ -338,6 +356,8 @@ func (this *DetailAction) RunGet(params struct {
|
||||
"cacheTotalDiskSize": numberutils.FormatBytes(status.CacheTotalDiskSize),
|
||||
"cacheTotalMemorySize": numberutils.FormatBytes(status.CacheTotalMemorySize),
|
||||
"exePath": status.ExePath,
|
||||
"apiSuccessPercent": status.APISuccessPercent,
|
||||
"apiAvgCostSeconds": status.APIAvgCostSeconds,
|
||||
},
|
||||
|
||||
"group": groupMap,
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
@@ -57,9 +58,19 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
}
|
||||
|
||||
var diskSubDirs = []*serverconfigs.CacheDir{}
|
||||
if len(node.CacheDiskSubDirsJSON) > 0 {
|
||||
err = json.Unmarshal(node.CacheDiskSubDirsJSON, &diskSubDirs)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var nodeMap = this.Data["node"].(maps.Map)
|
||||
nodeMap["maxCacheDiskCapacity"] = maxCacheDiskCapacity
|
||||
nodeMap["cacheDiskDir"] = node.CacheDiskDir
|
||||
nodeMap["cacheDiskSubDirs"] = diskSubDirs
|
||||
nodeMap["maxCacheMemoryCapacity"] = maxCacheMemoryCapacity
|
||||
|
||||
this.Show()
|
||||
@@ -69,6 +80,7 @@ func (this *IndexAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
MaxCacheDiskCapacityJSON []byte
|
||||
CacheDiskDir string
|
||||
CacheDiskSubDirsJSON []byte
|
||||
MaxCacheMemoryCapacityJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
@@ -105,10 +117,20 @@ func (this *IndexAction) RunPost(params struct {
|
||||
}
|
||||
}
|
||||
|
||||
if len(params.CacheDiskSubDirsJSON) > 0 {
|
||||
var cacheSubDirs = []*serverconfigs.CacheDir{}
|
||||
err := json.Unmarshal(params.CacheDiskSubDirsJSON, &cacheSubDirs)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_, err := this.RPC().NodeRPC().UpdateNodeCache(this.AdminContext(), &pb.UpdateNodeCacheRequest{
|
||||
NodeId: params.NodeId,
|
||||
MaxCacheDiskCapacity: pbMaxCacheDiskCapacity,
|
||||
CacheDiskDir: params.CacheDiskDir,
|
||||
CacheDiskSubDirsJSON: params.CacheDiskSubDirsJSON,
|
||||
MaxCacheMemoryCapacity: pbMaxCacheMemoryCapacity,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/cluster/node/nodeutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
@@ -50,6 +51,22 @@ func (this *IndexAction) RunGet(params struct {
|
||||
}
|
||||
this.Data["dnsResolverConfig"] = dnsResolverConfig
|
||||
|
||||
// API相关
|
||||
apiConfigResp, err := this.RPC().NodeRPC().FindNodeAPIConfig(this.AdminContext(), &pb.FindNodeAPIConfigRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var apiNodeAddrs = []*serverconfigs.NetworkAddressConfig{}
|
||||
if len(apiConfigResp.ApiNodeAddrsJSON) > 0 {
|
||||
err = json.Unmarshal(apiConfigResp.ApiNodeAddrsJSON, &apiNodeAddrs)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
this.Data["apiNodeAddrs"] = apiNodeAddrs
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -59,6 +76,8 @@ func (this *IndexAction) RunPost(params struct {
|
||||
|
||||
DnsResolverJSON []byte
|
||||
|
||||
ApiNodeAddrsJSON []byte
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
@@ -68,6 +87,7 @@ func (this *IndexAction) RunPost(params struct {
|
||||
this.Fail("CPU线程数不能小于0")
|
||||
}
|
||||
|
||||
// 系统设置
|
||||
_, err := this.RPC().NodeRPC().UpdateNodeSystem(this.AdminContext(), &pb.UpdateNodeSystemRequest{
|
||||
NodeId: params.NodeId,
|
||||
MaxCPU: params.MaxCPU,
|
||||
@@ -77,6 +97,7 @@ func (this *IndexAction) RunPost(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
// DNS解析设置
|
||||
var dnsResolverConfig = nodeconfigs.DefaultDNSResolverConfig()
|
||||
err = json.Unmarshal(params.DnsResolverJSON, dnsResolverConfig)
|
||||
if err != nil {
|
||||
@@ -98,5 +119,28 @@ func (this *IndexAction) RunPost(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
// API节点设置
|
||||
var apiNodeAddrs = []*serverconfigs.NetworkAddressConfig{}
|
||||
if len(params.ApiNodeAddrsJSON) > 0 {
|
||||
err = json.Unmarshal(params.ApiNodeAddrsJSON, &apiNodeAddrs)
|
||||
if err != nil {
|
||||
this.Fail("API节点地址校验错误:" + err.Error())
|
||||
}
|
||||
for _, addr := range apiNodeAddrs {
|
||||
err = addr.Init()
|
||||
if err != nil {
|
||||
this.Fail("API节点地址校验错误:" + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
_, err = this.RPC().NodeRPC().UpdateNodeAPIConfig(this.AdminContext(), &pb.UpdateNodeAPIConfigRequest{
|
||||
NodeId: params.NodeId,
|
||||
ApiNodeAddrsJSON: params.ApiNodeAddrsJSON,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
// 默认值
|
||||
@@ -122,6 +136,7 @@ func (this *IndexAction) RunPost(params struct {
|
||||
AutoOpenPorts bool
|
||||
ClockAutoSync bool
|
||||
ClockServer string
|
||||
ClockCheckChrony bool
|
||||
AutoRemoteStart bool
|
||||
AutoInstallNftables bool
|
||||
|
||||
@@ -154,6 +169,7 @@ func (this *IndexAction) RunPost(params struct {
|
||||
var clockConfig = nodeconfigs.DefaultClockConfig()
|
||||
clockConfig.AutoSync = params.ClockAutoSync
|
||||
clockConfig.Server = params.ClockServer
|
||||
clockConfig.CheckChrony = params.ClockCheckChrony
|
||||
clockConfigJSON, err := json.Marshal(clockConfig)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -60,7 +60,7 @@ func (this *ClusterHelper) BeforeAction(actionPtr actions.ActionWrapper) (goNext
|
||||
var tabbar = actionutils.NewTabbar()
|
||||
tabbar.Add("集群列表", "", "/clusters", "", false)
|
||||
if teaconst.IsPlus {
|
||||
tabbar.Add("集群看板", "", "/clusters/cluster/boards?clusterId="+clusterIdString, "board", selectedTabbar == "board")
|
||||
tabbar.Add("集群看板", "", "/clusters/cluster/boards?clusterId="+clusterIdString, "chart line area", selectedTabbar == "board")
|
||||
}
|
||||
tabbar.Add("集群节点", "", "/clusters/cluster/nodes?clusterId="+clusterIdString, "server", selectedTabbar == "node")
|
||||
tabbar.Add("集群设置", "", "/clusters/cluster/settings?clusterId="+clusterIdString, "setting", selectedTabbar == "setting")
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -71,7 +71,10 @@ func ValidateRecordName(name string) bool {
|
||||
}
|
||||
|
||||
pieces := strings.Split(name, ".")
|
||||
for _, piece := range pieces {
|
||||
for index, piece := range pieces {
|
||||
if index == 0 && piece == "*" {
|
||||
continue
|
||||
}
|
||||
if piece == "-" ||
|
||||
strings.HasPrefix(piece, "-") ||
|
||||
strings.HasSuffix(piece, "-") ||
|
||||
@@ -130,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字节"
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ func (this *CreateRulePopupAction) RunGet(params struct {
|
||||
"params": checkpoint.Params,
|
||||
"options": checkpoint.Options,
|
||||
"isComposed": checkpoint.IsComposed,
|
||||
"dataType": checkpoint.DataType,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -21,14 +21,14 @@ func (this *DeleteAction) RunPost(params struct {
|
||||
defer this.CreateLog(oplogs.LevelInfo, "删除请求Header,HeaderPolicyId:%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)
|
||||
|
||||
@@ -19,12 +19,12 @@ func (this *DeleteDeletingHeaderAction) RunPost(params struct {
|
||||
// 日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "删除需要删除的请求Header,HeaderPolicyId:%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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -19,6 +19,7 @@ func init() {
|
||||
GetPost("/createDeletePopup", new(CreateDeletePopupAction)).
|
||||
Post("/deleteDeletingHeader", new(DeleteDeletingHeaderAction)).
|
||||
Post("/delete", new(DeleteAction)).
|
||||
GetPost("/updateCORSPopup", new(UpdateCORSPopupAction)).
|
||||
EndAll()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package uam
|
||||
package referers
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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()
|
||||
})
|
||||
}
|
||||
@@ -39,10 +39,11 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
KeepArgs bool
|
||||
|
||||
// 域名
|
||||
DomainsAll bool
|
||||
DomainsBeforeJSON []byte
|
||||
DomainAfter string
|
||||
DomainAfterScheme string
|
||||
DomainsAll bool
|
||||
DomainsBeforeJSON []byte
|
||||
DomainBeforeIgnorePorts bool
|
||||
DomainAfter string
|
||||
DomainAfterScheme string
|
||||
|
||||
// 端口
|
||||
PortsAll bool
|
||||
@@ -128,6 +129,7 @@ func (this *CreatePopupAction) RunPost(params struct {
|
||||
return
|
||||
}
|
||||
}
|
||||
config.DomainBeforeIgnorePorts = params.DomainBeforeIgnorePorts
|
||||
if len(params.DomainAfter) == 0 {
|
||||
this.FailField("domainAfter", "请输入跳转后域名")
|
||||
return
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package uam
|
||||
package referers
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package userui
|
||||
package userAgent
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/settingutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/servers/serverutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
|
||||
"github.com/iwind/TeaGo"
|
||||
)
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
func init() {
|
||||
TeaGo.BeforeStart(func(server *TeaGo.Server) {
|
||||
server.
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeCommon)).
|
||||
Helper(settingutils.NewHelper("userUI")).
|
||||
Prefix("/settings/user-ui").
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeServer)).
|
||||
Helper(serverutils.NewServerHelper()).
|
||||
Prefix("/servers/server/settings/userAgent").
|
||||
GetPost("", new(IndexAction)).
|
||||
EndAll()
|
||||
})
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
package userui
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"io"
|
||||
)
|
||||
|
||||
type IndexAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *IndexAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
config, err := configloaders.LoadUserUIConfig()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
this.Data["config"] = config
|
||||
|
||||
// 时区
|
||||
this.Data["timeZoneGroups"] = nodeconfigs.FindAllTimeZoneGroups()
|
||||
this.Data["timeZoneLocations"] = nodeconfigs.FindAllTimeZoneLocations()
|
||||
|
||||
if len(config.TimeZone) == 0 {
|
||||
config.TimeZone = nodeconfigs.DefaultTimeZoneLocation
|
||||
}
|
||||
this.Data["timeZoneLocation"] = nodeconfigs.FindTimeZoneLocation(config.TimeZone)
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
func (this *IndexAction) RunPost(params struct {
|
||||
ProductName string
|
||||
UserSystemName string
|
||||
ShowOpenSourceInfo bool
|
||||
ShowVersion bool
|
||||
Version string
|
||||
ShowFinance bool
|
||||
FaviconFile *actions.File
|
||||
LogoFile *actions.File
|
||||
TimeZone string
|
||||
|
||||
ShowTrafficCharts bool
|
||||
ShowBandwidthCharts bool
|
||||
BandwidthUnit string
|
||||
|
||||
Must *actions.Must
|
||||
CSRF *actionutils.CSRF
|
||||
}) {
|
||||
params.Must.
|
||||
Field("productName", params.ProductName).
|
||||
Require("请输入产品名称").
|
||||
Field("userSystemName", params.UserSystemName).
|
||||
Require("请输入管理员系统名称")
|
||||
|
||||
config, err := configloaders.LoadUserUIConfig()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
config.ProductName = params.ProductName
|
||||
config.UserSystemName = params.UserSystemName
|
||||
config.ShowOpenSourceInfo = params.ShowOpenSourceInfo
|
||||
config.ShowVersion = params.ShowVersion
|
||||
config.Version = params.Version
|
||||
config.ShowFinance = params.ShowFinance
|
||||
config.ShowTrafficCharts = params.ShowTrafficCharts
|
||||
config.ShowBandwidthCharts = params.ShowBandwidthCharts
|
||||
config.BandwidthUnit = params.BandwidthUnit
|
||||
config.TimeZone = params.TimeZone
|
||||
|
||||
// 上传Favicon文件
|
||||
if params.FaviconFile != nil {
|
||||
createResp, err := this.RPC().FileRPC().CreateFile(this.AdminContext(), &pb.CreateFileRequest{
|
||||
Filename: params.FaviconFile.Filename,
|
||||
Size: params.FaviconFile.Size,
|
||||
IsPublic: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
fileId := createResp.FileId
|
||||
|
||||
// 上传内容
|
||||
buf := make([]byte, 512*1024)
|
||||
reader, err := params.FaviconFile.OriginFile.Open()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
n, err := reader.Read(buf)
|
||||
if n > 0 {
|
||||
_, err = this.RPC().FileChunkRPC().CreateFileChunk(this.AdminContext(), &pb.CreateFileChunkRequest{
|
||||
FileId: fileId,
|
||||
Data: buf[:n],
|
||||
})
|
||||
if err != nil {
|
||||
this.Fail("上传失败:" + err.Error())
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
this.Fail("上传失败:" + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// 置为已完成
|
||||
_, err = this.RPC().FileRPC().UpdateFileFinished(this.AdminContext(), &pb.UpdateFileFinishedRequest{FileId: fileId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
}
|
||||
config.FaviconFileId = fileId
|
||||
}
|
||||
|
||||
// 上传Logo文件
|
||||
if params.LogoFile != nil {
|
||||
createResp, err := this.RPC().FileRPC().CreateFile(this.AdminContext(), &pb.CreateFileRequest{
|
||||
Filename: params.LogoFile.Filename,
|
||||
Size: params.LogoFile.Size,
|
||||
IsPublic: true,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
fileId := createResp.FileId
|
||||
|
||||
// 上传内容
|
||||
buf := make([]byte, 512*1024)
|
||||
reader, err := params.LogoFile.OriginFile.Open()
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
n, err := reader.Read(buf)
|
||||
if n > 0 {
|
||||
_, err = this.RPC().FileChunkRPC().CreateFileChunk(this.AdminContext(), &pb.CreateFileChunkRequest{
|
||||
FileId: fileId,
|
||||
Data: buf[:n],
|
||||
})
|
||||
if err != nil {
|
||||
this.Fail("上传失败:" + err.Error())
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
this.Fail("上传失败:" + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// 置为已完成
|
||||
_, err = this.RPC().FileRPC().UpdateFileFinished(this.AdminContext(), &pb.UpdateFileFinishedRequest{FileId: fileId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
}
|
||||
config.LogoFileId = fileId
|
||||
}
|
||||
|
||||
err = configloaders.UpdateUserUIConfig(config)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
this.Success()
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -31,10 +32,21 @@ func (this *DetectDBAction) RunPost(params struct{}) {
|
||||
localPort = "3306"
|
||||
|
||||
var username = "root"
|
||||
for _, pass := range []string{"", "123456", "654321", "Aa_123456"} {
|
||||
var passwords = []string{"", "123456", "654321", "Aa_123456", "111111"}
|
||||
|
||||
// 使用 foolish-mysql 安装的MySQL
|
||||
localGeneratedPasswordData, err := os.ReadFile("/usr/local/mysql/generated-password.txt")
|
||||
if err == nil {
|
||||
var localGeneratedPassword = strings.TrimSpace(string(localGeneratedPasswordData))
|
||||
if len(localGeneratedPassword) > 0 {
|
||||
passwords = append(passwords, localGeneratedPassword)
|
||||
}
|
||||
}
|
||||
|
||||
for _, pass := range passwords {
|
||||
db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
|
||||
Driver: "mysql",
|
||||
Dsn: username + ":" + pass + "@tcp(" + configutils.QuoteIP(localHost) + ":" + localPort + ")/edges11111",
|
||||
Dsn: username + ":" + pass + "@tcp(" + configutils.QuoteIP(localHost) + ":" + localPort + ")/edges",
|
||||
Prefix: "",
|
||||
})
|
||||
if err == nil {
|
||||
|
||||
@@ -22,7 +22,7 @@ func (this *IndexAction) RunGet(params struct{}) {
|
||||
currentHost = host
|
||||
}
|
||||
}
|
||||
if net.ParseIP(currentHost) != nil {
|
||||
if net.ParseIP(currentHost) != nil && currentHost != "localhost" && currentHost != "127.0.0.1" {
|
||||
this.Data["currentHost"] = currentHost
|
||||
} else {
|
||||
this.Data["currentHost"] = ""
|
||||
|
||||
@@ -17,13 +17,17 @@ import (
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/gosock/pkg/gosock"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type InstallAction struct {
|
||||
actionutils.ParentAction
|
||||
|
||||
apiSetupFinished bool
|
||||
}
|
||||
|
||||
func (this *InstallAction) RunPost(params struct {
|
||||
@@ -40,7 +44,7 @@ func (this *InstallAction) RunPost(params struct {
|
||||
|
||||
// API节点配置
|
||||
currentStatusText = "正在检查API节点配置"
|
||||
apiNodeMap := maps.Map{}
|
||||
var apiNodeMap = maps.Map{}
|
||||
err := json.Unmarshal(params.ApiNodeJSON, &apiNodeMap)
|
||||
if err != nil {
|
||||
this.Fail("API节点配置数据解析错误,请刷新页面后重新尝试安装,错误信息:" + err.Error())
|
||||
@@ -48,7 +52,7 @@ func (this *InstallAction) RunPost(params struct {
|
||||
|
||||
// 数据库
|
||||
currentStatusText = "正在检查数据库配置"
|
||||
dbMap := maps.Map{}
|
||||
var dbMap = maps.Map{}
|
||||
err = json.Unmarshal(params.DbJSON, &dbMap)
|
||||
if err != nil {
|
||||
this.Fail("数据库配置数据解析错误,请刷新页面后重新尝试安装,错误信息:" + err.Error())
|
||||
@@ -56,14 +60,14 @@ func (this *InstallAction) RunPost(params struct {
|
||||
|
||||
// 管理员
|
||||
currentStatusText = "正在检查管理员配置"
|
||||
adminMap := maps.Map{}
|
||||
var adminMap = maps.Map{}
|
||||
err = json.Unmarshal(params.AdminJSON, &adminMap)
|
||||
if err != nil {
|
||||
this.Fail("管理员数据解析错误,请刷新页面后重新尝试安装,错误信息:" + err.Error())
|
||||
}
|
||||
|
||||
// 安装API节点
|
||||
mode := apiNodeMap.GetString("mode")
|
||||
var mode = apiNodeMap.GetString("mode")
|
||||
if mode == "new" {
|
||||
currentStatusText = "准备启动新API节点"
|
||||
|
||||
@@ -74,7 +78,7 @@ func (this *InstallAction) RunPost(params struct {
|
||||
// ...
|
||||
|
||||
// 检查环境
|
||||
apiNodeDir := Tea.Root + "/edge-api"
|
||||
var apiNodeDir = Tea.Root + "/edge-api"
|
||||
for _, dir := range []string{"edge-api", "edge-api/configs", "edge-api/bin"} {
|
||||
apiNodeDir := Tea.Root + "/" + dir
|
||||
_, err = os.Stat(apiNodeDir)
|
||||
@@ -87,7 +91,7 @@ func (this *InstallAction) RunPost(params struct {
|
||||
}
|
||||
|
||||
// 保存数据库配置
|
||||
dsn := dbMap.GetString("username") + ":" + dbMap.GetString("password") + "@tcp(" + configutils.QuoteIP(dbMap.GetString("host")) + ":" + dbMap.GetString("port") + ")/" + dbMap.GetString("database") + "?charset=utf8mb4&timeout=30s"
|
||||
var dsn = dbMap.GetString("username") + ":" + dbMap.GetString("password") + "@tcp(" + configutils.QuoteIP(dbMap.GetString("host")) + ":" + dbMap.GetString("port") + ")/" + dbMap.GetString("database") + "?charset=utf8mb4&timeout=30s"
|
||||
dbConfig := &dbs.Config{
|
||||
DBs: map[string]*dbs.DBConfig{
|
||||
"prod": {
|
||||
@@ -108,7 +112,7 @@ func (this *InstallAction) RunPost(params struct {
|
||||
|
||||
// 生成备份文件
|
||||
homeDir, _ := os.UserHomeDir()
|
||||
backupDirs := []string{"/etc/edge-api"}
|
||||
var backupDirs = []string{"/etc/edge-api"}
|
||||
if len(homeDir) > 0 {
|
||||
backupDirs = append(backupDirs, homeDir+"/.edge-api")
|
||||
}
|
||||
@@ -151,15 +155,21 @@ func (this *InstallAction) RunPost(params struct {
|
||||
var resultMap = maps.Map{}
|
||||
logs.Println("[INSTALL]setup edge-api")
|
||||
{
|
||||
cmd := exec.Command(apiNodeDir+"/bin/edge-api", "setup", "-api-node-protocol=http", "-api-node-host=\""+apiNodeMap.GetString("newHost")+"\"", "-api-node-port=\""+apiNodeMap.GetString("newPort")+"\"")
|
||||
output := bytes.NewBuffer([]byte{})
|
||||
this.apiSetupFinished = false
|
||||
var cmd = exec.Command(apiNodeDir+"/bin/edge-api", "setup", "-api-node-protocol=http", "-api-node-host=\""+apiNodeMap.GetString("newHost")+"\"", "-api-node-port=\""+apiNodeMap.GetString("newPort")+"\"")
|
||||
var output = bytes.NewBuffer([]byte{})
|
||||
cmd.Stdout = output
|
||||
|
||||
// 试图读取执行日志
|
||||
go this.startReadingAPIInstallLog()
|
||||
|
||||
err = cmd.Run()
|
||||
this.apiSetupFinished = true
|
||||
if err != nil {
|
||||
this.Fail("安装失败:" + err.Error())
|
||||
}
|
||||
|
||||
resultData := output.Bytes()
|
||||
var resultData = output.Bytes()
|
||||
err = json.Unmarshal(resultData, &resultMap)
|
||||
if err != nil {
|
||||
this.Fail("安装节点时返回数据错误:" + err.Error() + "(" + string(resultData) + ")")
|
||||
@@ -175,7 +185,7 @@ func (this *InstallAction) RunPost(params struct {
|
||||
// 关闭正在运行的API节点,防止冲突
|
||||
logs.Println("[INSTALL]stop edge-api")
|
||||
{
|
||||
cmd := exec.Command(apiNodeDir+"/bin/edge-api", "stop")
|
||||
var cmd = exec.Command(apiNodeDir+"/bin/edge-api", "stop")
|
||||
_ = cmd.Run()
|
||||
}
|
||||
|
||||
@@ -183,7 +193,7 @@ func (this *InstallAction) RunPost(params struct {
|
||||
currentStatusText = "正在启动API节点"
|
||||
logs.Println("[INSTALL]start edge-api")
|
||||
{
|
||||
cmd := exec.Command(apiNodeDir + "/bin/edge-api")
|
||||
var cmd = exec.Command(apiNodeDir + "/bin/edge-api")
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
this.Fail("API节点启动失败:" + err.Error())
|
||||
@@ -220,7 +230,7 @@ func (this *InstallAction) RunPost(params struct {
|
||||
}
|
||||
|
||||
// 写入API节点配置,完成安装
|
||||
apiConfig := &configs.APIConfig{
|
||||
var apiConfig = &configs.APIConfig{
|
||||
RPC: struct {
|
||||
Endpoints []string `yaml:"endpoints"`
|
||||
DisableUpdate bool `yaml:"disableUpdate"`
|
||||
@@ -283,7 +293,7 @@ func (this *InstallAction) RunPost(params struct {
|
||||
this.Success()
|
||||
} else if mode == "old" {
|
||||
// 构造RPC
|
||||
apiConfig := &configs.APIConfig{
|
||||
var apiConfig = &configs.APIConfig{
|
||||
RPC: struct {
|
||||
Endpoints []string `yaml:"endpoints"`
|
||||
DisableUpdate bool `yaml:"disableUpdate"`
|
||||
@@ -303,7 +313,7 @@ func (this *InstallAction) RunPost(params struct {
|
||||
}()
|
||||
|
||||
// 设置管理员
|
||||
ctx := client.APIContext(0)
|
||||
var ctx = client.APIContext(0)
|
||||
_, err = client.AdminRPC().CreateOrUpdateAdmin(ctx, &pb.CreateOrUpdateAdminRequest{
|
||||
Username: adminMap.GetString("username"),
|
||||
Password: adminMap.GetString("password"),
|
||||
@@ -344,3 +354,73 @@ func (this *InstallAction) RunPost(params struct {
|
||||
this.Fail("错误的API节点模式:'" + mode + "'")
|
||||
}
|
||||
}
|
||||
|
||||
// 读取API安装时的日志,以便于显示当前正在执行的任务
|
||||
func (this *InstallAction) startReadingAPIInstallLog() {
|
||||
var tmpDir = os.TempDir()
|
||||
if len(tmpDir) == 0 {
|
||||
return
|
||||
}
|
||||
var logFile = tmpDir + "/edge-install.log"
|
||||
|
||||
var logFp *os.File
|
||||
var err error
|
||||
|
||||
// 尝试5秒钟
|
||||
for i := 0; i < 10; i++ {
|
||||
logFp, err = os.Open(logFile)
|
||||
if err != nil {
|
||||
time.Sleep(1 * time.Second)
|
||||
continue
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if this.apiSetupFinished {
|
||||
_ = logFp.Close()
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
_ = logFp.Close()
|
||||
}()
|
||||
|
||||
var ticker = time.NewTicker(1 * time.Second)
|
||||
var logBuf = make([]byte, 256)
|
||||
for range ticker.C {
|
||||
if this.apiSetupFinished {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = logFp.Seek(-256, io.SeekEnd)
|
||||
if err != nil {
|
||||
currentStatusText = ""
|
||||
return
|
||||
}
|
||||
|
||||
n, err := logFp.Read(logBuf)
|
||||
if err != nil {
|
||||
currentStatusText = ""
|
||||
return
|
||||
}
|
||||
|
||||
if n > 0 {
|
||||
var logData = string(logBuf[:n])
|
||||
var lines = strings.Split(logData, "\n")
|
||||
if len(lines) >= 3 {
|
||||
var line = strings.TrimSpace(lines[len(lines)-2])
|
||||
if len(line) > 0 {
|
||||
if !this.apiSetupFinished {
|
||||
currentStatusText = "正在执行 " + line + " ..."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -25,7 +25,7 @@ func init() {
|
||||
Get("/otpQrcode", new(OtpQrcodeAction)).
|
||||
|
||||
// AccessKeys
|
||||
Prefix("/users/accessKeys").
|
||||
Prefix("/users/accesskeys").
|
||||
Get("", new(accesskeys.IndexAction)).
|
||||
GetPost("/createPopup", new(accesskeys.CreatePopupAction)).
|
||||
Post("/delete", new(accesskeys.DeleteAction)).
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"
|
||||
@@ -124,7 +126,6 @@ import (
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/ui"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/updates"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/upgrade"
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/user-ui"
|
||||
|
||||
// 恢复
|
||||
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/recover"
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -35,7 +35,7 @@ Vue.component("checkbox", {
|
||||
this.newValue = ""
|
||||
},
|
||||
isChecked: function () {
|
||||
return this.newValue == this.elementValue
|
||||
return (typeof (this.newValue) == "boolean" && this.newValue) || this.newValue == this.elementValue
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
@@ -38,6 +38,13 @@ Vue.component("datepicker", {
|
||||
watch: {
|
||||
value: function (v) {
|
||||
this.day = v
|
||||
|
||||
let picker = this.$refs.dayInput.picker
|
||||
if (picker != null) {
|
||||
if (v != null && /^\d+-\d+-\d+$/.test(v)) {
|
||||
picker.setDate(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -54,8 +54,6 @@ Vue.component("datetime-input", {
|
||||
},
|
||||
methods: {
|
||||
change: function () {
|
||||
let date = new Date()
|
||||
|
||||
// day
|
||||
if (!/^\d{4}-\d{1,2}-\d{1,2}$/.test(this.day)) {
|
||||
this.hasDayError = true
|
||||
@@ -63,21 +61,18 @@ Vue.component("datetime-input", {
|
||||
}
|
||||
let pieces = this.day.split("-")
|
||||
let year = parseInt(pieces[0])
|
||||
date.setFullYear(year)
|
||||
|
||||
let month = parseInt(pieces[1])
|
||||
if (month < 1 || month > 12) {
|
||||
this.hasDayError = true
|
||||
return
|
||||
}
|
||||
date.setMonth(month - 1)
|
||||
|
||||
let day = parseInt(pieces[2])
|
||||
if (day < 1 || day > 32) {
|
||||
this.hasDayError = true
|
||||
return
|
||||
}
|
||||
date.setDate(day)
|
||||
|
||||
this.hasDayError = false
|
||||
|
||||
@@ -96,7 +91,6 @@ Vue.component("datetime-input", {
|
||||
return
|
||||
}
|
||||
this.hasHourError = false
|
||||
date.setHours(hour)
|
||||
|
||||
// minute
|
||||
if (!/^\d+$/.test(this.minute)) {
|
||||
@@ -113,7 +107,6 @@ Vue.component("datetime-input", {
|
||||
return
|
||||
}
|
||||
this.hasMinuteError = false
|
||||
date.setMinutes(minute)
|
||||
|
||||
// second
|
||||
if (!/^\d+$/.test(this.second)) {
|
||||
@@ -130,8 +123,8 @@ Vue.component("datetime-input", {
|
||||
return
|
||||
}
|
||||
this.hasSecondError = false
|
||||
date.setSeconds(second)
|
||||
|
||||
let date = new Date(year, month - 1, day, hour, minute, second)
|
||||
this.timestamp = Math.floor(date.getTime() / 1000)
|
||||
},
|
||||
leadingZero: function (s, l) {
|
||||
|
||||
@@ -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>'
|
||||
|
||||
@@ -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"/>
|
||||
<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>
|
||||
|
||||
@@ -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> <a href="" @click.prevent="cancel()"><i class="icon remove small"></i></a>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
79
web/public/js/components/node/node-cache-disk-dirs-box.js
Normal file
79
web/public/js/components/node/node-cache-disk-dirs-box.js
Normal file
@@ -0,0 +1,79 @@
|
||||
Vue.component("node-cache-disk-dirs-box", {
|
||||
props: ["value", "name"],
|
||||
data: function () {
|
||||
let dirs = this.value
|
||||
if (dirs == null) {
|
||||
dirs = []
|
||||
}
|
||||
return {
|
||||
dirs: dirs,
|
||||
|
||||
isEditing: false,
|
||||
isAdding: false,
|
||||
|
||||
addingPath: ""
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
add: function () {
|
||||
this.isAdding = true
|
||||
let that = this
|
||||
setTimeout(function () {
|
||||
that.$refs.addingPath.focus()
|
||||
}, 100)
|
||||
},
|
||||
confirm: function () {
|
||||
let addingPath = this.addingPath.trim()
|
||||
if (addingPath.length == 0) {
|
||||
let that = this
|
||||
teaweb.warn("请输入要添加的缓存目录", function () {
|
||||
that.$refs.addingPath.focus()
|
||||
})
|
||||
return
|
||||
}
|
||||
if (addingPath[0] != "/") {
|
||||
addingPath = "/" + addingPath
|
||||
}
|
||||
this.dirs.push({
|
||||
path: addingPath
|
||||
})
|
||||
this.cancel()
|
||||
},
|
||||
cancel: function () {
|
||||
this.addingPath = ""
|
||||
this.isAdding = false
|
||||
this.isEditing = false
|
||||
},
|
||||
remove: function (index) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除此目录吗?", function () {
|
||||
that.dirs.$remove(index)
|
||||
})
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
<input type="hidden" :name="name" :value="JSON.stringify(dirs)"/>
|
||||
<div style="margin-bottom: 0.3em">
|
||||
<span class="ui label small basic" v-for="(dir, index) in dirs">
|
||||
<i class="icon folder"></i>{{dir.path}} <a href="" title="删除" @click.prevent="remove(index)"><i class="icon remove small"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- 添加 -->
|
||||
<div v-if="isAdding">
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" style="width: 30em" v-model="addingPath" @keyup.enter="confirm()" @keypress.enter.prevent="1" @keydown.esc="cancel()" ref="addingPath" placeholder="新的缓存目录,比如 /mnt/cache"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button small" type="button" @click.prevent="confirm">确定</button>
|
||||
<a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!isAdding">
|
||||
<button class="ui button tiny" type="button" @click.prevent="add">+</button>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
@@ -13,9 +13,9 @@ Vue.component("ns-access-log-box", {
|
||||
if (accessLog.recordValue == null || accessLog.recordValue.length == 0) {
|
||||
isFailure = true
|
||||
}
|
||||
} else if (accessLog.nsRecordId == null || accessLog.nsRecordId == 0) {
|
||||
isFailure = true
|
||||
}
|
||||
|
||||
// 没有找到记录的不需要高亮显示,防止管理员看到红色就心理恐慌
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -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">
|
||||
|
||||
<span v-if="range.connector == 'OR' || range.connector == '' || range.connector == null">或</span>
|
||||
<span v-if="range.connector == 'AND'">且</span>
|
||||
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<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">
|
||||
|
||||
<span v-if="regionConnector == 'OR' || regionConnector == ''">或</span>
|
||||
<span v-if="regionConnector == 'AND'">且</span>
|
||||
|
||||
</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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
102
web/public/js/components/senders/email-sender.js
Normal file
102
web/public/js/components/senders/email-sender.js
Normal 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>`
|
||||
})
|
||||
@@ -227,7 +227,7 @@ Vue.component("domains-box", {
|
||||
<a href="" title="取消" @click.prevent="cancel"><i class="icon remove small"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<p class="comment" v-if="supportWildcard">支持普通域名(<code-label>example.com</code-label>)、泛域名(<code-label>*.example.com</code-label>)、域名后缀(以点号开头,如<code-label>.example.com</code-label>)和正则表达式(以波浪号开头,如<code-label>~.*.example.com</code-label>)。</p>
|
||||
<p class="comment" v-if="supportWildcard">支持普通域名(<code-label>example.com</code-label>)、泛域名(<code-label>*.example.com</code-label>)<span v-if="vSupportWildcard == undefined">、域名后缀(以点号开头,如<code-label>.example.com</code-label>)和正则表达式(以波浪号开头,如<code-label>~.*.example.com</code-label>)</span>;如果域名后有端口,请加上端口号。</p>
|
||||
<p class="comment" v-if="!supportWildcard">只支持普通域名(<code-label>example.com</code-label>、<code-label>www.example.com</code-label>)。</p>
|
||||
<div class="ui divider"></div>
|
||||
</div>
|
||||
|
||||
@@ -59,7 +59,7 @@ Vue.component("firewall-syn-flood-config-box", {
|
||||
<td class="title">启用</td>
|
||||
<td>
|
||||
<checkbox v-model="config.isOn"></checkbox>
|
||||
<p class="comment">启用后,WAF将会尝试自动检测并阻止SYN Flood攻击。此功能需要节点已安装并启用Firewalld。</p>
|
||||
<p class="comment">启用后,WAF将会尝试自动检测并阻止SYN Flood攻击。此功能需要节点已安装并启用nftables或Firewalld。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -58,7 +58,7 @@ Vue.component("http-access-log-config-box", {
|
||||
<prior-checkbox :v-config="accessLog" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||
<tbody v-show="(!vIsLocation && !vIsGroup) || accessLog.isPrior">
|
||||
<tr>
|
||||
<td class="title">开启访问日志</td>
|
||||
<td class="title">启用访问日志</td>
|
||||
<td>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" v-model="accessLog.isOn"/>
|
||||
|
||||
@@ -82,7 +82,7 @@ Vue.component("http-access-log-search-box", {
|
||||
<a class="ui label basic" :class="{disabled: keyword.length == 0}" @click.prevent="cleanKeyword"><i class="icon remove small"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field"><tip-icon content="一些特殊的关键词:<br/>单个状态码:status:200<br/>状态码范围:status:500-504<br/>查询IP:ip:192.168.1.100<br/>查询URL:https://goedge.cn/docs<br/>查询路径部分:requestPath:/hello/world<br/>查询协议版本:proto:HTTP/1.1<br/>协议:scheme:http"></tip-icon></div>
|
||||
<div class="ui field"><tip-icon content="一些特殊的关键词:<br/>单个状态码:status:200<br/>状态码范围:status:500-504<br/>查询IP:ip:192.168.1.100<br/>查询URL:https://goedge.cn/docs<br/>查询路径部分:requestPath:/hello/world<br/>查询协议版本:proto:HTTP/1.1<br/>协议:scheme:http<br/>请求方法:method:POST"></tip-icon></div>
|
||||
</div>
|
||||
<div class="ui fields inline" style="margin-top: 0.5em">
|
||||
<div class="ui field">
|
||||
|
||||
@@ -26,7 +26,7 @@ Vue.component("http-charsets-box", {
|
||||
<prior-checkbox :v-config="charsetConfig" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||
<tbody v-show="(!vIsLocation && !vIsGroup) || charsetConfig.isPrior">
|
||||
<tr>
|
||||
<td class="title">启用</td>
|
||||
<td class="title">启用字符编码</td>
|
||||
<td>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" v-model="charsetConfig.isOn"/>
|
||||
|
||||
@@ -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"},
|
||||
mimeTypes: ["text/*", "application/*", "font/*"],
|
||||
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
|
||||
},
|
||||
@@ -153,7 +163,7 @@ Vue.component("http-compression-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>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" value="1" v-model="config.isOn"/>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>`
|
||||
})
|
||||
@@ -10,7 +10,21 @@ 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
|
||||
},
|
||||
isEmptyString: function (v) {
|
||||
return typeof v == "string" && v.length == 0
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
<div class="ui label tiny basic" style="line-height: 1.5">
|
||||
@@ -29,8 +43,9 @@ 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>
|
||||
{{rule.value}}
|
||||
<span :class="{dash:rule.isCaseInsensitive}" :title="rule.isCaseInsensitive ? '大小写不敏感':''" v-if="!rule.isComposed">{{operatorName(rule.operator)}}</span>
|
||||
<span v-if="!isEmptyString(rule.value)">{{rule.value}}</span>
|
||||
<span v-else class="disabled" style="font-weight: normal" title="空字符串">[空]</span>
|
||||
</span>
|
||||
|
||||
<!-- description -->
|
||||
|
||||
@@ -14,15 +14,17 @@ Vue.component("http-firewall-rules-box", {
|
||||
window.UPDATING_RULE = null
|
||||
let that = this
|
||||
teaweb.popup("/servers/components/waf/createRulePopup?type=" + this.vType, {
|
||||
height: "30em",
|
||||
callback: function (resp) {
|
||||
that.rules.push(resp.data.rule)
|
||||
}
|
||||
})
|
||||
},
|
||||
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",
|
||||
callback: function (resp) {
|
||||
Vue.set(that.rules, index, resp.data.rule)
|
||||
}
|
||||
@@ -33,12 +35,27 @@ 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
|
||||
},
|
||||
isEmptyString: function (v) {
|
||||
return typeof v == "string" && v.length == 0
|
||||
}
|
||||
},
|
||||
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 -->
|
||||
@@ -53,7 +70,9 @@ 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>
|
||||
<span v-if="!isEmptyString(rule.value)">{{rule.value}}</span>
|
||||
<span v-else class="disabled" style="font-weight: normal" title="空字符串">[空]</span>
|
||||
</span>
|
||||
|
||||
<!-- description -->
|
||||
|
||||
@@ -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"> </span>
|
||||
</span>`
|
||||
})
|
||||
@@ -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> <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> <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> <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> <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> <a href="" @click.prevent="updateCORS(vResponseHeaderPolicy.id)">[修改]</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="margin"></div>
|
||||
</div>`
|
||||
|
||||
@@ -130,6 +130,7 @@ Vue.component("http-host-redirect-box", {
|
||||
<div style="margin-top: 0.4em">
|
||||
<grey-label><strong>域名跳转</strong></grey-label>
|
||||
<grey-label v-if="redirect.domainAfterScheme != null && redirect.domainAfterScheme.length > 0">{{redirect.domainAfterScheme}}</grey-label>
|
||||
<grey-label v-if="redirect.domainBeforeIgnorePorts">忽略端口</grey-label>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="redirect.type == 'port'">
|
||||
|
||||
@@ -65,14 +65,14 @@ Vue.component("http-referers-config-box", {
|
||||
<tr>
|
||||
<td>允许的来源域名</td>
|
||||
<td>
|
||||
<values-box :values="config.allowDomains" @change="changeAllowDomains"></values-box>
|
||||
<domains-box :v-domains="config.allowDomains" @change="changeAllowDomains">></domains-box>
|
||||
<p class="comment">允许的其他来源域名列表,比如<code-label>example.com</code-label>、<code-label>*.example.com</code-label>。单个星号<code-label>*</code-label>表示允许所有域名。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>禁止的来源域名</td>
|
||||
<td>
|
||||
<values-box :values="config.denyDomains" @change="changeDenyDomains"></values-box>
|
||||
<domains-box :v-domains="config.denyDomains" @change="changeDenyDomains"></domains-box>
|
||||
<p class="comment">禁止的来源域名列表,比如<code-label>example.org</code-label>、<code-label>*.example.org</code-label>;除了这些禁止的来源域名外,其他域名都会被允许,除非限定了允许的来源域名。</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -18,7 +18,7 @@ Vue.component("http-stat-config-box", {
|
||||
<prior-checkbox :v-config="stat" v-if="vIsLocation || vIsGroup" ></prior-checkbox>
|
||||
<tbody v-show="(!vIsLocation && !vIsGroup) || stat.isPrior">
|
||||
<tr>
|
||||
<td class="title">是否开启统计</td>
|
||||
<td class="title">启用统计</td>
|
||||
<td>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" v-model="stat.isOn"/>
|
||||
|
||||
@@ -47,7 +47,7 @@ Vue.component("http-web-root-box", {
|
||||
<prior-checkbox :v-config="rootConfig" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||
<tbody v-show="(!vIsLocation && !vIsGroup) || rootConfig.isPrior">
|
||||
<tr>
|
||||
<td class="title">是否开启静态资源分发</td>
|
||||
<td class="title">启用静态资源分发</td>
|
||||
<td>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" v-model="rootConfig.isOn"/>
|
||||
|
||||
@@ -69,7 +69,7 @@ Vue.component("http-webp-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">启用WebP压缩</td>
|
||||
<td>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" value="1" v-model="config.isOn"/>
|
||||
|
||||
@@ -80,7 +80,7 @@ Vue.component("http-websocket-box", {
|
||||
<prior-checkbox :v-config="websocketRef" v-if="vIsLocation || vIsGroup"></prior-checkbox>
|
||||
<tbody v-show="((!vIsLocation && !vIsGroup) || websocketRef.isPrior)">
|
||||
<tr>
|
||||
<td class="title">启用配置</td>
|
||||
<td class="title">启用Websocket</td>
|
||||
<td>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" v-model="websocketRef.isOn"/>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
秒
|
||||
|
||||
@@ -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>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user