Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions core/cmd/server/cmd/reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"fmt"
"strings"

"github.com/1Panel-dev/1Panel/core/constant"
"github.com/1Panel-dev/1Panel/core/i18n"
Expand All @@ -17,13 +18,16 @@ func init() {

RootCmd.AddCommand(resetCmd)
resetCmd.AddCommand(resetMFACmd)
resetMFACmd.Flags().StringVar(&resetMFAUserNameFlag, "username", "", "username")
resetCmd.AddCommand(resetSSLCmd)
resetCmd.AddCommand(resetEntranceCmd)
resetCmd.AddCommand(resetBindIpsCmd)
resetCmd.AddCommand(resetDomainCmd)
resetCmd.AddCommand(resetPasskeyCmd)
}

var resetMFAUserNameFlag string

var resetCmd = &cobra.Command{
Use: "reset",
RunE: func(cmd *cobra.Command, args []string) error {
Expand All @@ -41,6 +45,29 @@ var resetMFACmd = &cobra.Command{
fmt.Println(i18n.GetMsgWithMapForCmd("SudoHelper", map[string]interface{}{"cmd": "sudo 1pctl reset mfa"}))
return nil
}
if isEnterprise() && len(strings.TrimSpace(resetMFAUserNameFlag)) == 0 {
fmt.Println(i18n.GetMsgByKeyForCmd("UsernameNeed"))
return nil
}
if isEnterprise() {
db, err := loadDBConn("enterprise.db")
if err != nil {
return err
}
username := strings.TrimSpace(resetMFAUserNameFlag)
var count int64
if err := db.Table("users").Where("name = ?", username).Count(&count).Error; err != nil {
return err
}
if count == 0 {
return fmt.Errorf("%s: %s", i18n.GetMsgByKeyForCmd("ErrRecordNotFound"), strings.TrimSpace(resetMFAUserNameFlag))
}
result := db.Exec("UPDATE users SET mfa_status = ? WHERE name = ?", constant.StatusDisable, username)
if result.Error != nil {
return result.Error
}
return nil
}
db, err := loadDBConn("core.db")
if err != nil {
return err
Expand Down
12 changes: 7 additions & 5 deletions core/cmd/server/cmd/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ var updateUserName = &cobra.Command{
return nil
}
if isEnterprise() && len(strings.TrimSpace(updateUserNameFlag)) == 0 {
fmt.Println(i18n.GetMsgByKey("UsernameNeed"))
fmt.Println(i18n.GetMsgByKeyForCmd("UsernameNeed"))
return nil
}
username()
Expand All @@ -77,7 +77,7 @@ var updatePassword = &cobra.Command{
return nil
}
if isEnterprise() && len(strings.TrimSpace(updatePasswordUserName)) == 0 {
fmt.Println(i18n.GetMsgByKey("UsernameNeed"))
fmt.Println(i18n.GetMsgByKeyForCmd("UsernameNeed"))
return nil
}
password()
Expand Down Expand Up @@ -268,16 +268,18 @@ func password() {
return
}
if err := updateEnterprisePassword(enterpriseDB, strings.TrimSpace(updatePasswordUserName), p); err != nil {
fmt.Println("\n", i18n.GetMsgWithMapForCmd("UpdatePortErr", map[string]interface{}{"err": err.Error()}))
fmt.Println("\n", i18n.GetMsgWithMapForCmd("UpdatePasswordErr", map[string]interface{}{"err": err.Error()}))
return
}
} else if err := setSettingByKey(db, "Password", p); err != nil {
fmt.Println("\n", i18n.GetMsgWithMapForCmd("UpdatePortErr", map[string]interface{}{"err": err.Error()}))
fmt.Println("\n", i18n.GetMsgWithMapForCmd("UpdatePasswordErr", map[string]interface{}{"err": err.Error()}))
return
}
username := getSettingByKey(db, "UserName")
username := ""
if isEnterprise() {
username = strings.TrimSpace(updatePasswordUserName)
} else {
username = getSettingByKey(db, "UserName")
}

fmt.Println("\n" + i18n.GetMsgByKeyForCmd("UpdateSuccessful"))
Expand Down
221 changes: 221 additions & 0 deletions core/cmd/server/cmd/user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
package cmd

import (
"fmt"
"time"

"github.com/1Panel-dev/1Panel/core/i18n"
"github.com/spf13/cobra"
"gorm.io/gorm"
)

func init() {
RootCmd.AddCommand(userListCmd)
}

var userListCmd = &cobra.Command{
Use: "user-list",
Short: i18n.GetMsgByKeyForCmd("UserList"),
RunE: func(cmd *cobra.Command, args []string) error {
i18n.UseI18nForCmd(language)
if !isRoot() {
fmt.Println(i18n.GetMsgWithMapForCmd("SudoHelper", map[string]interface{}{"cmd": "sudo 1pctl user-list"}))
return nil
}
if isEnterprise() {
db, err := loadDBConn("enterprise.db")
if err != nil {
return err
}
return listEnterpriseUsers(db)
}
db, err := loadDBConn("core.db")
if err != nil {
return err
}
return listCommunityUsers(db)
},
}

func listEnterpriseUsers(db *gorm.DB) error {
var userModels []enterpriseUserModel
if err := db.Order("created_at desc").Find(&userModels).Error; err != nil {
return err
}

rows := make([]enterpriseUserRow, 0, len(userModels))
for _, user := range userModels {
superAdmin := "no"
if user.IsSuperAdmin {
superAdmin = "yes"
}
rows = append(rows, enterpriseUserRow{
Name: user.Name,
MFAStatus: user.MFAStatus,
SuperAdmin: superAdmin,
CreatedAt: user.CreatedAt.Format(time.RFC3339),
})
}

if len(rows) == 0 {
fmt.Println(i18n.GetMsgByKeyForCmd("UserEmptyList"))
return nil
}

return printUserRows(rows)
}

func listCommunityUsers(db *gorm.DB) error {
nameSetting, err := loadSettingRecord(db, "UserName")
if err != nil {
return err
}
mfaSetting, err := loadSettingRecord(db, "MFAStatus")
if err != nil {
return err
}

rows := []enterpriseUserRow{
{
Name: nameSetting.Value,
MFAStatus: mfaSetting.Value,
SuperAdmin: "yes",
CreatedAt: createdAtString(nameSetting.CreatedAt),
},
}

return printUserRows(rows)
}

func printUserRows(rows []enterpriseUserRow) error {
headers := []string{
i18n.GetMsgByKeyForCmd("UserTableName"),
i18n.GetMsgByKeyForCmd("UserTableMFAStatus"),
i18n.GetMsgByKeyForCmd("UserTableSuperAdmin"),
i18n.GetMsgByKeyForCmd("UserTableCreatedAt"),
}
widths := make([]int, len(headers))
for i, header := range headers {
widths[i] = displayWidth(header)
}
for _, row := range rows {
values := []string{row.Name, row.MFAStatus, row.SuperAdmin, row.CreatedAt}
for i, value := range values {
if w := displayWidth(value); w > widths[i] {
widths[i] = w
}
}
}
fmt.Println(joinColumns(headers, widths))
for _, row := range rows {
fmt.Println(joinColumns([]string{row.Name, row.MFAStatus, row.SuperAdmin, row.CreatedAt}, widths))
}
return nil
}

func loadSettingRecord(db *gorm.DB, key string) (setting, error) {
var record setting
if err := db.Where("key = ?", key).First(&record).Error; err != nil {
return setting{}, err
}
return record, nil
}

func createdAtString(t time.Time) string {
if t.IsZero() {
return "-"
}
return t.Format(time.RFC3339)
}

type enterpriseUserRow struct {
Name string
MFAStatus string
SuperAdmin string
CreatedAt string
}

type enterpriseUserModel struct {
Name string
MFAStatus string
IsSuperAdmin bool
CreatedAt time.Time
}

func joinColumns(values []string, widths []int) string {
out := ""
for i, value := range values {
out += padDisplayWidth(value, widths[i])
if i != len(values)-1 {
out += " "
}
}
return out
}

func padDisplayWidth(value string, width int) string {
pad := width - displayWidth(value)
if pad <= 0 {
return value
}
return value + spaces(pad)
}

func spaces(n int) string {
if n <= 0 {
return ""
}
return fmt.Sprintf("%*s", n, "")
}

func displayWidth(s string) int {
width := 0
for _, r := range s {
width += runeDisplayWidth(r)
}
return width
}

func runeDisplayWidth(r rune) int {
if r == 0 {
return 0
}
if r < 32 || (r >= 0x7f && r < 0xa0) {
return 0
}
if isWideRune(r) {
return 2
}
return 1
}

func isWideRune(r rune) bool {
if r < 0x1100 {
return false
}
if r <= 0x115f || r == 0x2329 || r == 0x232a {
return true
}
if r >= 0x2e80 && r <= 0xa4cf && r != 0x303f {
return true
}
if r >= 0xac00 && r <= 0xd7a3 {
return true
}
if r >= 0xf900 && r <= 0xfaff {
return true
}
if r >= 0xfe10 && r <= 0xfe19 {
return true
}
if r >= 0xfe30 && r <= 0xfe6f {
return true
}
if r >= 0xff00 && r <= 0xff60 {
return true
}
if r >= 0xffe0 && r <= 0xffe6 {
return true
}
return r >= 0x20000 && r <= 0x3fffd
}
7 changes: 7 additions & 0 deletions core/i18n/lang/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ AppVersionExist: "Version already exists!"
AppCreateSuccessful: "Creation successful!"
AppWriteErr: "File {{ .name }} write failed {{ .err }}"
SudoHelper: "Use {{ .cmd }} or switch to root user"
UsernameNeed: "Enterprise edition must specify --username"
ListenIPCommands: "Switch listening ip"
ListenIPv4: "Listen on IPv4"
ListenIPv6: "Listen on IPv6"
Expand All @@ -219,6 +220,12 @@ ResetEntrance: "Cancel 1Panel secure entrance"
ResetIPs: "Cancel 1Panel authorized ip restrictions"
ResetDomain: "Cancel 1Panel domain binding"
ResetPasskey: "Clear 1Panel passkeys"
UserList: "Get 1Panel user list"
UserTableName: "Name"
UserTableMFAStatus: "MFA Status"
UserTableSuperAdmin: "Super Admin"
UserTableCreatedAt: "Created At"
UserEmptyList: "No users found"
RestoreCommands: "Roll back 1Panel service and data"
RestoreNoSuchFile: "No rollback files found"
RestoreStep1: "(1/5) Starting rollback of 1Panel service and data from {{ .name }} directory..."
Expand Down
7 changes: 7 additions & 0 deletions core/i18n/lang/es-ES.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ AppVersionExist: "La versión ya existe"
AppCreateSuccessful: "Creación finalizada con éxito"
AppWriteErr: "Error al escribir el archivo {{ .name }} {{ .err }}"
SudoHelper: "Por favor use {{ .cmd }} o cambie al usuario root"
UsernameNeed: "La edición Enterprise debe especificar --username"
ListenIPCommands: "Cambiar ip de escucha"
ListenIPv4: "Escuchar en IPv4"
ListenIPv6: "Escuchar en IPv6"
Expand All @@ -213,6 +214,12 @@ ResetEntrance: "Cancelar entrada segura de 1Panel"
ResetIPs: "Cancelar restricciones de IP autorizadas de 1Panel"
ResetDomain: "Cancelar vinculación de dominio de 1Panel"
ResetPasskey: "Eliminar passkeys de 1Panel"
UserList: "Obtener la lista de usuarios de 1Panel"
UserTableName: "Nombre"
UserTableMFAStatus: "Estado MFA"
UserTableSuperAdmin: "Superadministrador"
UserTableCreatedAt: "Creado en"
UserEmptyList: "No se encontraron usuarios"
RestoreCommands: "Revertir el servicio y los datos de 1Panel"
RestoreNoSuchFile: "No se encontraron archivos de reversión"
RestoreStep1: "(1/5) Iniciando la reversión del servicio y los datos de 1Panel desde el directorio {{ .name }}..."
Expand Down
7 changes: 7 additions & 0 deletions core/i18n/lang/ja.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ AppVersionExist: "バージョンはすでに存在します!"
AppCreateSuccessful: "創造は成功しました!"
AppWriteErr: "file {{ .name }} write failed {{ .err }}"
SudoHelper: "{{.cmd}}を使用するか、ルートユーザーに切り替えてください"
UsernameNeed: "Enterprise版では --username を指定する必要があります"
ListenIPCommands: "リスニングIPを切り替えます"
ListenIPv4: "IPv4で聞いてください"
ListenIPv6: "IPv6で聞く"
Expand All @@ -213,6 +214,12 @@ ResetEntrance: "1パネルの安全な入り口をキャンセルします"
ResetIPs: "1パネル認定IP制限をキャンセルします"
ResetDomain: "1パネルドメインバインディングをキャンセルします"
ResetPasskey: "1Panel のパスキーをクリアします"
UserList: "1Panel ユーザー一覧を取得します"
UserTableName: "名前"
UserTableMFAStatus: "MFA ステータス"
UserTableSuperAdmin: "スーパー管理者"
UserTableCreatedAt: "作成日時"
UserEmptyList: "ユーザーが見つかりません"
RestoreCommands: "1Panel のサービスとデータをロールバック"
RestoreNoSuchFile: "ロールバックに使えるファイルが見つかりません"
RestoreStep1: "(1/5){{ .name }} ディレクトリから 1Panel のサービスとデータのロールバックを開始しています..."
Expand Down
Loading
Loading