1
0
Эх сурвалжийг харах

update v0.9.4 for anylink

Stille 2 жил өмнө
parent
commit
a4030417e1

+ 0 - 5
anylink/.codecov.yml

@@ -1,5 +0,0 @@
-ignore:
-  - "screenshot"
-  - "web"
-  - "server/conf"
-  - "server/files"

+ 0 - 5
anylink/.gitignore

@@ -1,5 +0,0 @@
-# Binaries for programs and plugins
-.idea/
-anylink-deploy
-anylink-deploy.tar.gz
-

+ 1 - 1
anylink/Dockerfile

@@ -1,6 +1,6 @@
 # web
 FROM node:16.17.1-alpine3.15 as builder_node
-ENV VERSION 0.9.3
+ENV VERSION 0.9.4
 WORKDIR /web
 COPY ./web /web
 RUN yarn install \

+ 3 - 0
anylink/build.sh

@@ -12,6 +12,9 @@ function RETVAL() {
 #当前目录
 cpath=$(pwd)
 
+ver=`cat server/base/app_ver.go | grep APP_VER | awk '{print $3}' | sed 's/"//g'`
+echo "当前版本 $ver"
+
 echo "编译前端项目"
 cd $cpath/web
 #国内可替换源加快速度

+ 26 - 0
anylink/server/admin/api_base.go

@@ -8,6 +8,7 @@ import (
 	"github.com/bjdgyc/anylink/base"
 	"github.com/bjdgyc/anylink/pkg/utils"
 	"github.com/gorilla/mux"
+	"github.com/xlzd/gotp"
 )
 
 // Login 登陆接口
@@ -20,10 +21,35 @@ func Login(w http.ResponseWriter, r *http.Request) {
 	adminUser := r.PostFormValue("admin_user")
 	adminPass := r.PostFormValue("admin_pass")
 
+	// 启用otp验证
+	if base.Cfg.AdminOtp != "" {
+		pwd := adminPass
+		pl := len(pwd)
+		if pl < 6 {
+			RespError(w, RespUserOrPassErr)
+			base.Error(adminUser, "管理员otp错误")
+			return
+		}
+		// 判断otp信息
+		adminPass = pwd[:pl-6]
+		otp := pwd[pl-6:]
+
+		totp := gotp.NewDefaultTOTP(base.Cfg.AdminOtp)
+		unix := time.Now().Unix()
+		verify := totp.Verify(otp, int(unix))
+
+		if !verify {
+			RespError(w, RespUserOrPassErr)
+			base.Error(adminUser, "管理员otp错误")
+			return
+		}
+	}
+
 	// 认证错误
 	if !(adminUser == base.Cfg.AdminUser &&
 		utils.PasswordVerify(adminPass, base.Cfg.AdminPass)) {
 		RespError(w, RespUserOrPassErr)
+		base.Error(adminUser, "管理员用户名或密码错误")
 		return
 	}
 

+ 10 - 4
anylink/server/admin/api_uploaduser.go

@@ -5,11 +5,11 @@ import (
 	"io"
 	"net/http"
 	"os"
+	"path"
 	"strconv"
 	"strings"
 	"time"
 
-	"github.com/bjdgyc/anylink/base"
 	"github.com/bjdgyc/anylink/dbdata"
 	"github.com/bjdgyc/anylink/pkg/utils"
 	mapset "github.com/deckarep/golang-set"
@@ -25,21 +25,27 @@ func UserUpload(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	defer file.Close()
-	newFile, err := os.Create(base.Cfg.FilesPath + header.Filename)
+
+	// go/path-injection
+	// base.Cfg.FilesPath 可以直接对外访问,不能上传文件到此
+	fileName := path.Join(os.TempDir(), utils.RandomRunes(10))
+	newFile, err := os.Create(fileName)
 	if err != nil {
 		RespError(w, RespInternalErr, "创建文件失败:", err)
 		return
 	}
 	defer newFile.Close()
+
 	io.Copy(newFile, file)
 	if err = UploadUser(newFile.Name()); err != nil {
 		RespError(w, RespInternalErr, err)
-		os.Remove(base.Cfg.FilesPath + header.Filename)
+		os.Remove(fileName)
 		return
 	}
-	os.Remove(base.Cfg.FilesPath + header.Filename)
+	os.Remove(fileName)
 	RespSucess(w, "批量添加成功")
 }
+
 func UploadUser(file string) error {
 	f, err := excelize.OpenFile(file)
 	if err != nil {

+ 1 - 1
anylink/server/base/app_ver.go

@@ -3,5 +3,5 @@ package base
 const (
 	APP_NAME = "AnyLink"
 	// app版本号
-	APP_VER = "0.9.3"
+	APP_VER = "0.9.4"
 )

+ 1 - 0
anylink/server/base/cfg.go

@@ -49,6 +49,7 @@ type ServerConfig struct {
 	Issuer         string `json:"issuer"`
 	AdminUser      string `json:"admin_user"`
 	AdminPass      string `json:"admin_pass"`
+	AdminOtp       string `json:"admin_otp"`
 	JwtSecret      string `json:"jwt_secret"`
 
 	LinkMode    string `json:"link_mode"`    // tun tap macvtap ipvtap

+ 14 - 2
anylink/server/base/cmd.go

@@ -3,14 +3,17 @@ package base
 import (
 	"errors"
 	"fmt"
+	"io"
 	"os"
 	"reflect"
 	"runtime"
 	"strings"
 
 	"github.com/bjdgyc/anylink/pkg/utils"
+	"github.com/skip2/go-qrcode"
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
+	"github.com/xlzd/gotp"
 )
 
 var (
@@ -18,6 +21,8 @@ var (
 	CommitId string
 	// pass明文
 	passwd string
+	// 生成otp
+	otp bool
 	// 生成密钥
 	secret bool
 	// 显示版本信息
@@ -80,7 +85,6 @@ func initCmd() {
 	linkViper.SetEnvPrefix("link")
 
 	// 基础配置
-
 	for _, v := range configs {
 		if v.Typ == cfgStr {
 			rootCmd.Flags().StringP(v.Name, v.Short, v.ValStr, v.Usage)
@@ -113,7 +117,7 @@ func initCmd() {
 		linkViper.SetConfigFile(conf)
 		err = linkViper.ReadInConfig()
 		if err != nil {
-			fmt.Println("Using config file:", err)
+			panic("config file err:" + err.Error())
 		}
 	})
 }
@@ -128,6 +132,7 @@ func initToolCmd() *cobra.Command {
 	toolCmd.Flags().BoolVarP(&rev, "version", "v", false, "display version info")
 	toolCmd.Flags().BoolVarP(&secret, "secret", "s", false, "generate a random jwt secret")
 	toolCmd.Flags().StringVarP(&passwd, "passwd", "p", "", "convert the password plaintext")
+	toolCmd.Flags().BoolVarP(&otp, "otp", "o", false, "generate a random otp secret")
 	toolCmd.Flags().BoolVarP(&debug, "debug", "d", false, "list the config viper.Debug() info")
 
 	toolCmd.Run = func(cmd *cobra.Command, args []string) {
@@ -138,6 +143,13 @@ func initToolCmd() *cobra.Command {
 			s, _ := utils.RandSecret(40, 60)
 			s = strings.Trim(s, "=")
 			fmt.Printf("Secret:%s\n", s)
+		case otp:
+			s := gotp.RandomSecret(32)
+			fmt.Printf("Otp:%s\n\n", s)
+			qrstr := fmt.Sprintf("otpauth://totp/%s:%s?issuer=%s&secret=%s", "anylink_admin", "admin@anylink", "anylink_admin", s)
+			qr, _ := qrcode.New(qrstr, qrcode.High)
+			ss := qr.ToSmallString(false)
+			io.WriteString(os.Stderr, ss)
 		case passwd != "":
 			pass, _ := utils.PasswordHash(passwd)
 			fmt.Printf("Passwd:%s\n", pass)

+ 1 - 0
anylink/server/base/config.go

@@ -38,6 +38,7 @@ var configs = []config{
 	{Typ: cfgStr, Name: "issuer", Usage: "系统名称", ValStr: "XX公司VPN"},
 	{Typ: cfgStr, Name: "admin_user", Usage: "管理用户名", ValStr: "admin"},
 	{Typ: cfgStr, Name: "admin_pass", Usage: "管理用户密码", ValStr: defaultPwd},
+	{Typ: cfgStr, Name: "admin_otp", Usage: "管理用户otp,生成命令 ./anylink tool -o", ValStr: ""},
 	{Typ: cfgStr, Name: "jwt_secret", Usage: "JWT密钥", ValStr: defaultJwt},
 	{Typ: cfgStr, Name: "link_mode", Usage: "虚拟网络类型[tun tap macvtap ipvtap]", ValStr: "tun"},
 	{Typ: cfgStr, Name: "ipv4_master", Usage: "ipv4主网卡名称", ValStr: "eth0"},

+ 1 - 1
anylink/server/base/log.go

@@ -103,7 +103,7 @@ func logLevel2Int(l string) int {
 	}
 	lvl := LogLevelInfo
 	for k, v := range levels {
-		if strings.EqualFold(strings.ToLower(l), strings.ToLower(v)) {
+		if strings.ToLower(l) == strings.ToLower(v) {
 			lvl = k
 		}
 	}

+ 3 - 0
anylink/server/conf/server-sample.toml

@@ -23,6 +23,9 @@ issuer = "XX公司VPN"
 admin_user = "admin"
 #pass 123456
 admin_pass = "$2a$10$UQ7C.EoPifDeJh6d8.31TeSPQU7hM/NOM2nixmBucJpAuXDQNqNke"
+# 留空表示不开启 otp, 开启otp后密码为  pass + 6位otp
+# 生成 ./anylink tool -o
+admin_otp = ""
 jwt_secret = "abcdef.0123456789.abcdef"
 
 

+ 3 - 0
anylink/server/conf/server.toml

@@ -18,6 +18,9 @@ issuer = "XX公司VPN"
 admin_user = "admin"
 #pass 123456
 admin_pass = "$2a$10$UQ7C.EoPifDeJh6d8.31TeSPQU7hM/NOM2nixmBucJpAuXDQNqNke"
+# 留空表示不开启 otp, 开启otp后密码为  pass + 6位otp
+# 生成 ./anylink tool -o
+admin_otp = ""
 jwt_secret = "abcdef.0123456789.abcdef"
 
 #服务监听地址

+ 5 - 6
anylink/server/dbdata/cert.go

@@ -64,8 +64,7 @@ type DNSProvider struct {
 		SecretKey string `json:"secretKey"`
 	} `json:"txcloud"`
 	CfCloud struct {
-		AuthEmail string `json:"authEmail"`
-		AuthKey   string `json:"authKey"`
+		AuthToken string `json:"authToken"`
 	} `json:"cfcloud"`
 }
 type LegoUserData struct {
@@ -89,15 +88,15 @@ type LeGoClient struct {
 func GetDNSProvider(l *SettingLetsEncrypt) (Provider challenge.Provider, err error) {
 	switch l.Name {
 	case "aliyun":
-		if Provider, err = alidns.NewDNSProviderConfig(&alidns.Config{APIKey: l.DNSProvider.AliYun.APIKey, SecretKey: l.DNSProvider.AliYun.SecretKey, TTL: 600}); err != nil {
+		if Provider, err = alidns.NewDNSProviderConfig(&alidns.Config{APIKey: l.DNSProvider.AliYun.APIKey, SecretKey: l.DNSProvider.AliYun.SecretKey, PropagationTimeout: 60 * time.Second, PollingInterval: 2 * time.Second, TTL: 600}); err != nil {
 			return
 		}
 	case "txcloud":
-		if Provider, err = tencentcloud.NewDNSProviderConfig(&tencentcloud.Config{SecretID: l.DNSProvider.TXCloud.SecretID, SecretKey: l.DNSProvider.TXCloud.SecretKey, TTL: 600}); err != nil {
+		if Provider, err = tencentcloud.NewDNSProviderConfig(&tencentcloud.Config{SecretID: l.DNSProvider.TXCloud.SecretID, SecretKey: l.DNSProvider.TXCloud.SecretKey, PropagationTimeout: 60 * time.Second, PollingInterval: 2 * time.Second, TTL: 600}); err != nil {
 			return
 		}
-	case "cloudflare":
-		if Provider, err = cloudflare.NewDNSProviderConfig(&cloudflare.Config{AuthEmail: l.DNSProvider.CfCloud.AuthEmail, AuthKey: l.DNSProvider.CfCloud.AuthKey, TTL: 600}); err != nil {
+	case "cfcloud":
+		if Provider, err = cloudflare.NewDNSProviderConfig(&cloudflare.Config{AuthToken: l.DNSProvider.CfCloud.AuthToken, PropagationTimeout: 60 * time.Second, PollingInterval: 2 * time.Second, TTL: 600}); err != nil {
 			return
 		}
 	}

+ 2 - 3
anylink/server/dbdata/db.go

@@ -115,9 +115,8 @@ func addInitData() error {
 				SecretKey string `json:"secretKey"`
 			}{SecretID: "", SecretKey: ""},
 			CfCloud: struct {
-				AuthEmail string `json:"authEmail"`
-				AuthKey   string `json:"authKey"`
-			}{AuthEmail: "", AuthKey: ""}},
+				AuthToken string `json:"authToken"`
+			}{AuthToken: ""}},
 	}
 	err = SettingSessAdd(sess, provider)
 	if err != nil {

+ 15 - 2
anylink/server/dbdata/group.go

@@ -117,11 +117,18 @@ func SetGroup(g *Group) error {
 				continue
 			}
 
-			ipMask, _, err := parseIpNet(v.Val)
+			ipMask, ipNet, err := parseIpNet(v.Val)
+
 			if err != nil {
 				return errors.New("RouteInclude 错误" + err.Error())
 			}
 
+			// 给Mac系统下发路由时,必须是标准的网络地址
+			if strings.Split(ipMask, "/")[0] != ipNet.IP.String() {
+				errMsg := fmt.Sprintf("RouteInclude 错误: 网络地址错误,建议: %s 改为 %s", v.Val, ipNet)
+				return errors.New(errMsg)
+			}
+
 			v.IpMask = ipMask
 			routeInclude = append(routeInclude, v)
 		}
@@ -130,10 +137,16 @@ func SetGroup(g *Group) error {
 	routeExclude := []ValData{}
 	for _, v := range g.RouteExclude {
 		if v.Val != "" {
-			ipMask, _, err := parseIpNet(v.Val)
+			ipMask, ipNet, err := parseIpNet(v.Val)
 			if err != nil {
 				return errors.New("RouteExclude 错误" + err.Error())
 			}
+
+			if strings.Split(ipMask, "/")[0] != ipNet.IP.String() {
+				errMsg := fmt.Sprintf("RouteInclude 错误: 网络地址错误,建议: %s 改为 %s", v.Val, ipNet)
+				return errors.New(errMsg)
+			}
+
 			v.IpMask = ipMask
 			routeExclude = append(routeExclude, v)
 		}

+ 13 - 2
anylink/server/dbdata/policy.go

@@ -2,6 +2,7 @@ package dbdata
 
 import (
 	"errors"
+	"fmt"
 	"net"
 	"strings"
 	"time"
@@ -31,11 +32,16 @@ func SetPolicy(p *Policy) error {
 				continue
 			}
 
-			ipMask, _, err := parseIpNet(v.Val)
+			ipMask, ipNet, err := parseIpNet(v.Val)
 			if err != nil {
 				return errors.New("RouteInclude 错误" + err.Error())
 			}
 
+			if strings.Split(ipMask, "/")[0] != ipNet.IP.String() {
+				errMsg := fmt.Sprintf("RouteInclude 错误: 网络地址错误,建议: %s 改为 %s", v.Val, ipNet)
+				return errors.New(errMsg)
+			}
+
 			v.IpMask = ipMask
 			routeInclude = append(routeInclude, v)
 		}
@@ -45,10 +51,15 @@ func SetPolicy(p *Policy) error {
 	routeExclude := []ValData{}
 	for _, v := range p.RouteExclude {
 		if v.Val != "" {
-			ipMask, _, err := parseIpNet(v.Val)
+			ipMask, ipNet, err := parseIpNet(v.Val)
 			if err != nil {
 				return errors.New("RouteExclude 错误" + err.Error())
 			}
+
+			if strings.Split(ipMask, "/")[0] != ipNet.IP.String() {
+				errMsg := fmt.Sprintf("RouteInclude 错误: 网络地址错误,建议: %s 改为 %s", v.Val, ipNet)
+				return errors.New(errMsg)
+			}
 			v.IpMask = ipMask
 			routeExclude = append(routeExclude, v)
 		}

+ 4 - 4
anylink/server/dbdata/policy_test.go

@@ -21,19 +21,19 @@ func TestGetPolicy(t *testing.T) {
 	err = SetPolicy(&p2)
 	ast.Nil(err)
 
-	route := []ValData{{Val: "192.168.1.1/24"}}
+	route := []ValData{{Val: "192.168.1.0/24"}}
 	p3 := Policy{Username: "a3", ClientDns: []ValData{{Val: "114.114.114.114"}}, RouteInclude: route, DsExcludeDomains: "com.cn,qq.com"}
 	err = SetPolicy(&p3)
 	ast.Nil(err)
 	// 判断 IpMask
-	ast.Equal(p3.RouteInclude[0].IpMask, "192.168.1.1/255.255.255.0")
+	ast.Equal(p3.RouteInclude[0].IpMask, "192.168.1.0/255.255.255.0")
 
-	route2 := []ValData{{Val: "192.168.2.1/24"}}
+	route2 := []ValData{{Val: "192.168.2.0/24"}}
 	p4 := Policy{Username: "a4", ClientDns: []ValData{{Val: "114.114.114.114"}}, RouteExclude: route2, DsIncludeDomains: "com.cn,qq.com"}
 	err = SetPolicy(&p4)
 	ast.Nil(err)
 	// 判断 IpMask
-	ast.Equal(p4.RouteExclude[0].IpMask, "192.168.2.1/255.255.255.0")
+	ast.Equal(p4.RouteExclude[0].IpMask, "192.168.2.0/255.255.255.0")
 
 	// 判断所有数据
 	var userPolicy *Policy

+ 3 - 3
anylink/server/dbdata/user_test.go

@@ -17,12 +17,12 @@ func TestCheckUser(t *testing.T) {
 
 	// 添加一个组
 	dns := []ValData{{Val: "114.114.114.114"}}
-	route := []ValData{{Val: "192.168.1.1/24"}}
+	route := []ValData{{Val: "192.168.1.0/24"}}
 	g := Group{Name: group, Status: 1, ClientDns: dns, RouteInclude: route}
 	err := SetGroup(&g)
 	ast.Nil(err)
 	// 判断 IpMask
-	ast.Equal(g.RouteInclude[0].IpMask, "192.168.1.1/255.255.255.0")
+	ast.Equal(g.RouteInclude[0].IpMask, "192.168.1.0/255.255.255.0")
 
 	// 添加一个用户
 	u := User{Username: "aaa", Groups: []string{group}, Status: 1}
@@ -59,7 +59,7 @@ func TestCheckUser(t *testing.T) {
 	}
 	// 添加用户策略
 	dns2 := []ValData{{Val: "8.8.8.8"}}
-	route2 := []ValData{{Val: "192.168.2.1/24"}}
+	route2 := []ValData{{Val: "192.168.2.0/24"}}
 	p1 := Policy{Username: "aaa", Status: 1, ClientDns: dns2, RouteInclude: route2}
 	err = SetPolicy(&p1)
 	ast.Nil(err)

+ 10 - 11
anylink/server/go.mod

@@ -19,7 +19,7 @@ require (
 	github.com/lib/pq v1.10.2
 	github.com/mattn/go-sqlite3 v1.14.9
 	github.com/orcaman/concurrent-map v1.0.0
-	github.com/pion/dtls/v2 v2.2.6
+	github.com/pion/dtls/v2 v2.2.7
 	github.com/pion/logging v0.2.2
 	github.com/pires/go-proxyproto v0.6.2
 	github.com/shirou/gopsutil v3.21.7+incompatible
@@ -29,14 +29,14 @@ require (
 	github.com/spf13/cast v1.3.1
 	github.com/spf13/cobra v1.2.1
 	github.com/spf13/viper v1.8.1
-	github.com/stretchr/testify v1.8.1
+	github.com/stretchr/testify v1.8.3
 	github.com/xhit/go-simple-mail/v2 v2.10.0
 	github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119
 	github.com/xuri/excelize/v2 v2.6.1
 	go.uber.org/atomic v1.10.0
-	golang.org/x/crypto v0.5.0
-	golang.org/x/net v0.7.0
-	golang.org/x/text v0.7.0
+	golang.org/x/crypto v0.8.0
+	golang.org/x/net v0.9.0
+	golang.org/x/text v0.9.0
 	golang.org/x/time v0.3.0
 	layeh.com/radius v0.0.0-20210819152912-ad72663a72ab
 	xorm.io/xorm v1.3.2
@@ -54,13 +54,12 @@ require (
 	github.com/jmespath/go-jmespath v0.4.0 // indirect
 	github.com/kr/text v0.2.0 // indirect
 	github.com/miekg/dns v1.1.50 // indirect
-	github.com/pion/transport/v2 v2.0.2 // indirect
-	github.com/pion/udp/v2 v2.0.1 // indirect
+	github.com/pion/transport/v2 v2.2.1 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490 // indirect
 	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.490 // indirect
-	golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
-	golang.org/x/tools v0.1.12 // indirect
+	golang.org/x/mod v0.8.0 // indirect
+	golang.org/x/tools v0.6.0 // indirect
 )
 
 require (
@@ -94,8 +93,8 @@ require (
 	github.com/tklauser/numcpus v0.2.3 // indirect
 	github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 // indirect
 	github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect
-	golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
-	golang.org/x/sys v0.5.0 // indirect
+	golang.org/x/sync v0.1.0 // indirect
+	golang.org/x/sys v0.7.0 // indirect
 	gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
 	gopkg.in/ini.v1 v1.66.6 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect

+ 22 - 21
anylink/server/go.sum

@@ -472,14 +472,12 @@ github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko
 github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
 github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
 github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
-github.com/pion/dtls/v2 v2.2.6 h1:yXMxKr0Skd+Ub6A8UqXTRLSywskx93ooMRHsQUtd+Z4=
-github.com/pion/dtls/v2 v2.2.6/go.mod h1:t8fWJCIquY5rlQZwA2yWxUS1+OCrAdXrhVKXB5oD/wY=
+github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8=
+github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
 github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
 github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
-github.com/pion/transport/v2 v2.0.2 h1:St+8o+1PEzPT51O9bv+tH/KYYLMNR5Vwm5Z3Qkjsywg=
-github.com/pion/transport/v2 v2.0.2/go.mod h1:vrz6bUbFr/cjdwbnxq8OdDDzHf7JJfGsIRkxfpZoTA0=
-github.com/pion/udp/v2 v2.0.1 h1:xP0z6WNux1zWEjhC7onRA3EwwSliXqu1ElUZAQhUP54=
-github.com/pion/udp/v2 v2.0.1/go.mod h1:B7uvTMP00lzWdyMr/1PVZXtV3wpPIxBRd4Wl6AksXn8=
+github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N7c=
+github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
 github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Dos0d8=
 github.com/pires/go-proxyproto v0.6.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -578,8 +576,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
-github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
+github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
@@ -663,8 +661,8 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm
 golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
-golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
+golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
+golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -702,8 +700,9 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -750,9 +749,9 @@ golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qx
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
-golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
-golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
-golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
+golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -776,8 +775,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -843,14 +843,14 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
+golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 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/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
 golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -860,9 +860,9 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
 golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -929,8 +929,9 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
 golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
 golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

+ 1 - 1
anylink/server/handler/link_base.go

@@ -44,7 +44,7 @@ type macAddressList struct {
 
 func setCommonHeader(w http.ResponseWriter) {
 	// Content-Length Date 默认已经存在
-	w.Header().Set("Server", "AnyLink")
+	w.Header().Set("Server", "AnyLinkOpenSource")
 	w.Header().Set("Content-Type", "text/html; charset=utf-8")
 	w.Header().Set("Cache-Control", "no-store,no-cache")
 	w.Header().Set("Pragma", "no-cache")

+ 32 - 12
anylink/web/src/pages/group/List.vue

@@ -47,7 +47,12 @@
 
         <el-table-column
             prop="bandwidth"
-            label="带宽限制">
+            label="带宽限制"
+            width="90">
+            <template slot-scope="scope">
+                <el-row v-if="scope.row.bandwidth > 0">{{ convertBandwidth(scope.row.bandwidth, 'BYTE', 'Mbps') }} Mbps</el-row>
+                <el-row v-else>不限</el-row>
+            </template>            
         </el-table-column>
 
         <el-table-column
@@ -62,7 +67,7 @@
         <el-table-column
             prop="route_include"
             label="路由包含"
-            width="200">
+            width="180">
           <template slot-scope="scope">
             <el-row v-for="(item,inx) in scope.row.route_include.slice(0, readMinRows)" :key="inx">{{ item.val }}</el-row>
             <div v-if="scope.row.route_include.length > readMinRows">
@@ -77,7 +82,7 @@
         <el-table-column
             prop="route_exclude"
             label="路由排除"
-            width="200">
+            width="180">
           <template slot-scope="scope">
             <el-row v-for="(item,inx) in scope.row.route_exclude.slice(0, readMinRows)" :key="inx">{{ item.val }}</el-row>
             <div v-if="scope.row.route_exclude.length > readMinRows">
@@ -92,7 +97,7 @@
         <el-table-column
             prop="link_acl"
             label="LINK-ACL"
-            min-width="200">
+            min-width="180">
           <template slot-scope="scope">
             <el-row v-for="(item,inx) in scope.row.link_acl.slice(0, readMinRows)" :key="inx">
               {{ item.action }} => {{ item.val }} : {{ item.port }}
@@ -186,9 +191,9 @@
                 <el-input v-model="ruleForm.note"></el-input>
                 </el-form-item>
 
-                <el-form-item label="带宽限制" prop="bandwidth">
-                <el-input v-model.number="ruleForm.bandwidth">
-                    <template slot="append">BYTE/S</template>
+                <el-form-item label="带宽限制" prop="bandwidth_format" style="width:260px;">
+                <el-input v-model="ruleForm.bandwidth_format" oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''">
+                    <template slot="append">Mbps</template>
                 </el-input>
                 </el-form-item>
                 <el-form-item label="排除本地网络" prop="allow_lan">
@@ -266,7 +271,7 @@
                   </el-form-item>                  
                   <el-form-item label="用户唯一ID" prop="auth.ldap.search_attr" :rules="this.ruleForm.auth.type== 'ldap' ? this.rules['auth.ldap.search_attr'] : [{ required: false }]">
                     <el-input v-model="ruleForm.auth.ldap.search_attr" placeholder="例如 sAMAccountName / uid / cn"></el-input>
-                  </el-form-item>    
+                  </el-form-item>
                   <el-form-item label="受限用户组" prop="auth.ldap.member_of">
                     <el-input v-model="ruleForm.auth.ldap.member_of" placeholder="选填, 只允许指定组登入, 例如 CN=HomeWork,DC=abc,DC=com"></el-input>
                   </el-form-item>                                                                      
@@ -435,6 +440,7 @@ export default {
       },          
       ruleForm: {
         bandwidth: 0,
+        bandwidth_format: '0',
         status: 1,
         allow_lan: true,
         client_dns: [{val: '114.114.114.114'}],
@@ -463,9 +469,9 @@ export default {
           {required: true, message: '请输入组名', trigger: 'blur'},
           {max: 30, message: '长度小于 30 个字符', trigger: 'blur'}
         ],
-        bandwidth: [
+        bandwidth_format: [
           {required: true, message: '请输入带宽限制', trigger: 'blur'},
-          {type: 'number', message: '带宽限制必须为数字值'}
+          {type: 'string', message: '带宽限制必须为数字值'}
         ],
         status: [
           {required: true}
@@ -493,7 +499,7 @@ export default {
         ],        
         "auth.ldap.search_attr": [
           {required: true, message: '请输入用户唯一ID', trigger: 'blur'}
-        ],                                       
+        ],
       },
     }
   },
@@ -536,7 +542,8 @@ export default {
           id: row.id,
         }
       }).then(resp => {
-        this.ruleForm = resp.data.data;
+        resp.data.data.bandwidth_format = this.convertBandwidth(resp.data.data.bandwidth, 'BYTE', 'Mbps').toString();
+        this.ruleForm = resp.data.data;        
         this.setAuthData(resp.data.data);
       }).catch(error => {
         this.$message.error('哦,请求出错');
@@ -582,6 +589,7 @@ export default {
           console.log('error submit!!');
           return false;
         }
+        this.ruleForm.bandwidth = this.convertBandwidth(this.ruleForm.bandwidth_format, 'Mbps', 'BYTE');
         axios.post('/group/set', this.ruleForm).then(resp => {
           const rdata = resp.data;
           if (rdata.code === 0) {
@@ -666,6 +674,18 @@ export default {
     closeDialog() {
       this.user_edit_dialog = false;
       this.activeTab = "general";
+    },
+    convertBandwidth(bandwidth, fromUnit, toUnit) {
+        const units = {
+            bps: 1,
+            Kbps: 1000,
+            Mbps: 1000000,
+            Gbps: 1000000000,
+            BYTE: 8,
+        };
+        const result = bandwidth * units[fromUnit] / units[toUnit];
+        const fixedResult = result.toFixed(2);
+        return parseFloat(fixedResult);
     }
   },
 }

+ 12 - 11
anylink/web/src/pages/set/Other.vue

@@ -318,8 +318,7 @@ export default {
           secretKey: "",
         },
         cfcloud: {
-          authEmail: "",
-          authKey: "",
+          authToken: "",
         },
       },
       customCert: { cert: "", key: "" },
@@ -399,19 +398,13 @@ export default {
         ],
         cfcloud: [
           {
-            label: "Email",
-            prop: "email",
-            component: "el-input",
-            type: "text",
-          },
-          {
-            label: "AuthKey",
-            prop: "authKey",
+            label: "AuthToken",
+            prop: "authToken",
             component: "el-input",
             type: "password",
             rules: {
               required: true,
-              message: "请输入正确的APIKey",
+              message: "请输入正确的AuthToken",
               trigger: "blur",
             },
           },
@@ -551,12 +544,20 @@ export default {
               });
             break;
           case "letsCert":
+            var loading = this.$loading({
+              lock: true,
+              text: "证书申请中...",
+              spinner: "el-icon-loading",
+              background: "rgba(0, 0, 0, 0.7)",
+            });
             axios.post("/set/other/createcert", this.letsCert).then((resp) => {
               var rdata = resp.data;
               console.log(rdata);
               if (rdata.code === 0) {
+                loading.close();
                 this.$message.success(rdata.msg);
               } else {
+                loading.close();
                 this.$message.error(rdata.msg);
               }
             });