From fd4c3f2f2e4abf3a5e302d086d6ac66bcdadb4d6 Mon Sep 17 00:00:00 2001 From: ssongliu <73214554+ssongliu@users.noreply.github.com> Date: Mon, 4 Dec 2023 15:40:09 +0800 Subject: [PATCH] =?UTF-8?q?feat:=201pctl=20=E6=94=AF=E6=8C=81=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E9=9D=A2=E6=9D=BF=E4=BF=A1=E6=81=AF=20(#3163)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/server/cmd/update.go | 234 ++++++++++++++++++++++++++++++++++++ cmd/server/cmd/user-info.go | 19 +-- go.mod | 2 +- 3 files changed, 239 insertions(+), 16 deletions(-) create mode 100644 cmd/server/cmd/update.go diff --git a/cmd/server/cmd/update.go b/cmd/server/cmd/update.go new file mode 100644 index 000000000..605d23646 --- /dev/null +++ b/cmd/server/cmd/update.go @@ -0,0 +1,234 @@ +package cmd + +import ( + "bufio" + "fmt" + "os" + "strconv" + "strings" + "unicode" + + "github.com/1Panel-dev/1Panel/backend/global" + "github.com/1Panel-dev/1Panel/backend/utils/cmd" + "github.com/1Panel-dev/1Panel/backend/utils/common" + "github.com/1Panel-dev/1Panel/backend/utils/encrypt" + "github.com/spf13/cobra" + "golang.org/x/term" +) + +func init() { + RootCmd.AddCommand(updateCmd) + updateCmd.AddCommand(updateUserName) + updateCmd.AddCommand(updatePassword) + updateCmd.AddCommand(updatePort) +} + +var updateCmd = &cobra.Command{ + Use: "update", + Short: "修改面板信息", +} + +var updateUserName = &cobra.Command{ + Use: "username", + Short: "修改面板用户", + RunE: func(cmd *cobra.Command, args []string) error { + if !isRoot() { + fmt.Println("请使用 sudo 1pctl update username 或者切换到 root 用户") + return nil + } + username() + return nil + }, +} +var updatePassword = &cobra.Command{ + Use: "password", + Short: "修改面板密码", + RunE: func(cmd *cobra.Command, args []string) error { + if !isRoot() { + fmt.Println("请使用 sudo 1pctl update password 或者切换到 root 用户") + return nil + } + password() + return nil + }, +} +var updatePort = &cobra.Command{ + Use: "port", + Short: "修改面板端口", + RunE: func(cmd *cobra.Command, args []string) error { + if !isRoot() { + fmt.Println("请使用 sudo 1pctl update port 或者切换到 root 用户") + return nil + } + port() + return nil + }, +} + +func username() { + reader := bufio.NewReader(os.Stdin) + fmt.Print("修改面板用户: ") + newUsername, _ := reader.ReadString('\n') + newUsername = strings.Trim(newUsername, "\n") + if len(newUsername) == 0 { + fmt.Println("错误:输入面板用户为空!") + return + } + if strings.Contains(newUsername, " ") { + fmt.Println("错误:输入面板用户中包含空格字符!") + return + } + + db, err := loadDBConn() + if err != nil { + fmt.Printf("错误:初始化数据库连接失败,%v\n", err) + return + } + if err := setSettingByKey(db, "UserName", newUsername); err != nil { + fmt.Printf("错误:面板用户修改失败,%v\n", err) + return + } + + fmt.Printf("修改成功!\n\n") + fmt.Printf("面板用户:%s\n", newUsername) +} + +func password() { + fmt.Print("设置面板密码:") + bytePassword, err := term.ReadPassword(int(os.Stdin.Fd())) + if err != nil { + fmt.Printf("\n错误:面板密码信息读取错误,%v\n", err) + return + } + newPassword := string(bytePassword) + newPassword = strings.Trim(newPassword, "\n") + + if len(newPassword) == 0 { + fmt.Println("\n错误:输入面板密码为空!") + return + } + if strings.Contains(newPassword, " ") { + fmt.Println("\n错误:输入面板密码中包含空格字符!") + return + } + db, err := loadDBConn() + if err != nil { + fmt.Printf("\n错误:初始化数据库连接失败,%v\n", err) + return + } + complexSetting := getSettingByKey(db, "ComplexityVerification") + if complexSetting == "enable" { + if isValidPassword("newPassword") { + fmt.Println("\n错误:面板密码仅支持字母、数字、特殊字符(!@#$%*_,.?),长度 8-30 位!") + return + } + } + + fmt.Print("\n确认密码:") + byteConfirmPassword, err := term.ReadPassword(int(os.Stdin.Fd())) + if err != nil { + fmt.Printf("\n错误:面板密码信息读取错误,%v\n", err) + return + } + confirmPassword := string(byteConfirmPassword) + confirmPassword = strings.Trim(confirmPassword, "\n") + + if newPassword != confirmPassword { + fmt.Printf("\n错误:两次密码不匹配,请检查后重试!,%v\n", err) + return + } + + p := "" + encryptSetting := getSettingByKey(db, "EncryptKey") + if len(encryptSetting) == 16 { + global.CONF.System.EncryptKey = encryptSetting + p, _ = encrypt.StringEncrypt(newPassword) + } else { + p = newPassword + } + if err := setSettingByKey(db, "Password", p); err != nil { + fmt.Printf("\n错误:面板密码修改失败,%v\n", err) + return + } + username := getSettingByKey(db, "UserName") + + fmt.Printf("\n修改成功!\n\n") + fmt.Printf("面板用户:%s\n", username) + fmt.Printf("面板密码:%s\n", string(newPassword)) +} + +func port() { + reader := bufio.NewReader(os.Stdin) + fmt.Print("修改面板端口:") + + newPortStr, _ := reader.ReadString('\n') + newPortStr = strings.Trim(newPortStr, "\n") + newPort, err := strconv.Atoi(strings.TrimSpace(newPortStr)) + if err != nil { + fmt.Printf("错误:面板端口信息读取错误,%v\n", err) + return + } + if newPort < 0 || newPort > 65535 { + fmt.Println("错误:输入的端口号必须在 1 到 65535 之间!") + return + } + if common.ScanPort(newPort) { + fmt.Println("错误:该端口号正被占用,请检查后重试!") + return + } + db, err := loadDBConn() + if err != nil { + fmt.Printf("错误:初始化数据库连接失败,%v\n", err) + return + } + if err := setSettingByKey(db, "ServerPort", newPortStr); err != nil { + fmt.Printf("错误:面板端口修改失败,%v\n", err) + return + } + + fmt.Printf("修改成功!\n\n") + fmt.Printf("面板端口:%s\n", newPortStr) + + std, err := cmd.Exec("1pctl restart") + if err != nil { + fmt.Println(std) + } +} +func isValidPassword(password string) bool { + numCount := 0 + alphaCount := 0 + specialCount := 0 + + for _, char := range password { + switch { + case unicode.IsDigit(char): + numCount++ + case unicode.IsLetter(char): + alphaCount++ + case isSpecialChar(char): + specialCount++ + } + } + + if len(password) < 8 && len(password) > 30 { + return false + } + if (numCount == 0 && alphaCount == 0) || (alphaCount == 0 && specialCount == 0) || (numCount == 0 && specialCount == 0) { + return false + } + return true +} + +func isSpecialChar(char rune) bool { + specialChars := "!@#$%*_,.?" + return unicode.IsPunct(char) && contains(specialChars, char) +} + +func contains(specialChars string, char rune) bool { + for _, c := range specialChars { + if c == char { + return true + } + } + return false +} diff --git a/cmd/server/cmd/user-info.go b/cmd/server/cmd/user-info.go index 951342a82..c7a3ec925 100644 --- a/cmd/server/cmd/user-info.go +++ b/cmd/server/cmd/user-info.go @@ -3,8 +3,6 @@ package cmd import ( "fmt" - "github.com/1Panel-dev/1Panel/backend/global" - "github.com/1Panel-dev/1Panel/backend/utils/encrypt" "github.com/spf13/cobra" ) @@ -14,7 +12,7 @@ func init() { var userinfoCmd = &cobra.Command{ Use: "user-info", - Short: "获取用户信息", + Short: "获取面板信息", RunE: func(cmd *cobra.Command, args []string) error { if !isRoot() { fmt.Println("请使用 sudo 1pctl user-info 或者切换到 root 用户") @@ -25,21 +23,11 @@ var userinfoCmd = &cobra.Command{ return fmt.Errorf("init my db conn failed, err: %v \n", err) } user := getSettingByKey(db, "UserName") - password := getSettingByKey(db, "Password") port := getSettingByKey(db, "ServerPort") ssl := getSettingByKey(db, "SSL") entrance := getSettingByKey(db, "SecurityEntrance") - encryptSetting := getSettingByKey(db, "EncryptKey") address := getSettingByKey(db, "SystemIP") - p := "" - if len(encryptSetting) == 16 { - global.CONF.System.EncryptKey = encryptSetting - p, _ = encrypt.StringDecrypt(password) - } else { - p = password - } - protocol := "http" if ssl == "enable" { protocol = "https" @@ -49,8 +37,9 @@ var userinfoCmd = &cobra.Command{ } fmt.Printf("面板地址: %s://%s:%s/%s \n", protocol, address, port, entrance) - fmt.Printf("用户名称: %s\n", user) - fmt.Printf("用户密码: %s\n", p) + fmt.Println("面板用户: ", user) + fmt.Println("面板密码: ", "********") + fmt.Println("提示:修改密码可执行命令:1pctl update password") return nil }, } diff --git a/go.mod b/go.mod index 10f9ea4b2..bf7e81c96 100644 --- a/go.mod +++ b/go.mod @@ -55,6 +55,7 @@ require ( golang.org/x/net v0.17.0 golang.org/x/oauth2 v0.11.0 golang.org/x/sys v0.13.0 + golang.org/x/term v0.13.0 golang.org/x/text v0.13.0 gopkg.in/ini.v1 v1.67.0 gopkg.in/square/go-jose.v2 v2.6.0 @@ -224,7 +225,6 @@ require ( golang.org/x/image v0.10.0 // indirect golang.org/x/mod v0.11.0 // indirect golang.org/x/sync v0.4.0 // indirect - golang.org/x/term v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.10.0 // indirect google.golang.org/appengine v1.6.7 // indirect