mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/1Panel-dev/1Panel.git
synced 2026-09-20 08:03:55 +08:00
fix: improve security entrance and user commands (#12770)
This commit is contained in:
committed by
zhengkunwang223
parent
9d3313fe11
commit
e7578a9fc5
@@ -2,6 +2,7 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/constant"
|
||||
"github.com/1Panel-dev/1Panel/core/i18n"
|
||||
@@ -17,6 +18,7 @@ func init() {
|
||||
|
||||
RootCmd.AddCommand(resetCmd)
|
||||
resetCmd.AddCommand(resetMFACmd)
|
||||
resetMFACmd.Flags().StringVar(&resetMFAUserNameFlag, "username", "", "username")
|
||||
resetCmd.AddCommand(resetSSLCmd)
|
||||
resetCmd.AddCommand(resetEntranceCmd)
|
||||
resetCmd.AddCommand(resetBindIpsCmd)
|
||||
@@ -24,6 +26,8 @@ func init() {
|
||||
resetCmd.AddCommand(resetPasskeyCmd)
|
||||
}
|
||||
|
||||
var resetMFAUserNameFlag string
|
||||
|
||||
var resetCmd = &cobra.Command{
|
||||
Use: "reset",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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"))
|
||||
|
||||
221
core/cmd/server/cmd/user.go
Normal file
221
core/cmd/server/cmd/user.go
Normal file
@@ -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
|
||||
}
|
||||
@@ -209,6 +209,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"
|
||||
@@ -220,6 +221,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..."
|
||||
|
||||
@@ -203,6 +203,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"
|
||||
@@ -214,6 +215,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 }}..."
|
||||
|
||||
@@ -203,6 +203,7 @@ AppVersionExist: "バージョンはすでに存在します!"
|
||||
AppCreateSuccessful: "創造は成功しました!"
|
||||
AppWriteErr: "file {{ .name }} write failed {{ .err }}"
|
||||
SudoHelper: "{{.cmd}}を使用するか、ルートユーザーに切り替えてください"
|
||||
UsernameNeed: "Enterprise版では --username を指定する必要があります"
|
||||
ListenIPCommands: "リスニングIPを切り替えます"
|
||||
ListenIPv4: "IPv4で聞いてください"
|
||||
ListenIPv6: "IPv6で聞く"
|
||||
@@ -214,6 +215,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 のサービスとデータのロールバックを開始しています..."
|
||||
|
||||
@@ -202,6 +202,7 @@ AppVersionExist: "버전이 이미 존재합니다"
|
||||
AppCreateSuccessful: "생성 성공"
|
||||
AppWriteErr: "파일 {{ .name }} 쓰기 실패 {{ .err }}"
|
||||
SudoHelper: "{{ .cmd }} 명령을 사용하거나 root 사용자로 전환하세요."
|
||||
UsernameNeed: "Enterprise 버전은 --username을 지정해야 합니다"
|
||||
ListenIPCommands: "IP 변경"
|
||||
ListenIPv4: "IPv4 에서 수신 대기"
|
||||
ListenIPv6: "IPv6 에서 수신 대기"
|
||||
@@ -213,6 +214,12 @@ ResetEntrance: "1Panel 보안 입구 취소"
|
||||
ResetIPs: "1Panel 허용 IP 제한 취소"
|
||||
ResetDomain: "1Panel 도메인 바인딩 취소"
|
||||
ResetPasskey: "1Panel 패스키 초기화"
|
||||
UserList: "1Panel 사용자 목록 가져오기"
|
||||
UserTableName: "이름"
|
||||
UserTableMFAStatus: "MFA 상태"
|
||||
UserTableSuperAdmin: "슈퍼 관리자"
|
||||
UserTableCreatedAt: "생성일"
|
||||
UserEmptyList: "사용자를 찾을 수 없습니다"
|
||||
RestoreCommands: "1Panel 서비스와 데이터를 롤백"
|
||||
RestoreNoSuchFile: "롤백 파일을 찾을 수 없습니다"
|
||||
RestoreStep1: "(1/5) {{ .name }} 디렉터리에서 1Panel 서비스와 데이터의 롤백을 시작합니다..."
|
||||
|
||||
@@ -197,6 +197,7 @@ AppVersionExist: "Versi sudah wujud"
|
||||
AppCreateSuccessful: "Ciptaan berjaya"
|
||||
AppWriteErr: "Penulisan fail {{ .name }} gagal {{ .err }}"
|
||||
SudoHelper: "Sila gunakan {{ .cmd }} atau tukar ke pengguna root"
|
||||
UsernameNeed: "Edisi Enterprise mesti menentukan --username"
|
||||
ListenIPCommands: "Tukar IP mendengar"
|
||||
ListenIPv4: "Mendengar pada IPv4"
|
||||
ListenIPv6: "Mendengar pada IPv6"
|
||||
@@ -208,6 +209,12 @@ ResetEntrance: "Batal pintu masuk keselamatan 1Panel"
|
||||
ResetIPs: "Batal sekatan IP yang dibenarkan 1Panel"
|
||||
ResetDomain: "Batal pengikatan domain 1Panel"
|
||||
ResetPasskey: "Kosongkan passkey 1Panel"
|
||||
UserList: "Dapatkan senarai pengguna 1Panel"
|
||||
UserTableName: "Nama"
|
||||
UserTableMFAStatus: "Status MFA"
|
||||
UserTableSuperAdmin: "Pentadbir Super"
|
||||
UserTableCreatedAt: "Dicipta Pada"
|
||||
UserEmptyList: "Tiada pengguna ditemui"
|
||||
RestoreCommands: "Rollback perkhidmatan dan data 1Panel"
|
||||
RestoreNoSuchFile: "Tiada fail rollback ditemui"
|
||||
RestoreStep1: "(1/5) Memulakan rollback perkhidmatan dan data 1Panel daripada direktori {{ .name }}..."
|
||||
|
||||
@@ -202,6 +202,7 @@ AppVersionExist: "A versão já existe"
|
||||
AppCreateSuccessful: "Criação bem-sucedida"
|
||||
AppWriteErr: "Falha ao escrever no arquivo {{ .name }} {{ .err }}"
|
||||
SudoHelper: "Por favor, use {{ .cmd }} ou altere para o usuário root"
|
||||
UsernameNeed: "A edição Enterprise deve especificar --username"
|
||||
ListenIPCommands: "Trocar IP de escuta"
|
||||
ListenIPv4: "Escutando em IPv4"
|
||||
ListenIPv6: "Escutando em IPv6"
|
||||
@@ -213,6 +214,12 @@ ResetEntrance: "Cancelar entrada segura do 1Panel"
|
||||
ResetIPs: "Cancelar restrições de IP autorizado do 1Panel"
|
||||
ResetDomain: "Cancelar vinculação de domínio do 1Panel"
|
||||
ResetPasskey: "Redefinir passkeys do 1Panel"
|
||||
UserList: "Obter a lista de usuários do 1Panel"
|
||||
UserTableName: "Nome"
|
||||
UserTableMFAStatus: "Status MFA"
|
||||
UserTableSuperAdmin: "Superadministrador"
|
||||
UserTableCreatedAt: "Criado em"
|
||||
UserEmptyList: "Nenhum usuário encontrado"
|
||||
RestoreCommands: "Fazer rollback do serviço e dos dados do 1Panel"
|
||||
RestoreNoSuchFile: "Nenhum arquivo de rollback encontrado"
|
||||
RestoreStep1: "(1/5) Iniciando o rollback do serviço e dos dados do 1Panel a partir do diretório {{ .name }}..."
|
||||
|
||||
@@ -201,6 +201,7 @@ AppVersionExist: "Версия уже существует"
|
||||
AppCreateSuccessful: "Успешно создано"
|
||||
AppWriteErr: "Не удалось записать файл {{ .name }} {{ .err }}"
|
||||
SudoHelper: "Пожалуйста, используйте {{ .cmd }} или переключитесь на пользователя root"
|
||||
UsernameNeed: "Для Enterprise-версии необходимо указать --username"
|
||||
ListenIPCommands: "Переключить IP для прослушивания"
|
||||
ListenIPv4: "Прослушивание IPv4"
|
||||
ListenIPv6: "Прослушивание IPv6"
|
||||
@@ -212,6 +213,12 @@ ResetEntrance: "Отменить безопасный вход 1Panel"
|
||||
ResetIPs: "Отменить ограничения авторизованных IP для 1Panel"
|
||||
ResetDomain: "Отменить привязку домена доступа 1Panel"
|
||||
ResetPasskey: "Сбросить passkey 1Panel"
|
||||
UserList: "Получить список пользователей 1Panel"
|
||||
UserTableName: "Имя"
|
||||
UserTableMFAStatus: "Статус MFA"
|
||||
UserTableSuperAdmin: "Суперадмин"
|
||||
UserTableCreatedAt: "Создано"
|
||||
UserEmptyList: "Пользователи не найдены"
|
||||
RestoreCommands: "Откатить сервис и данные 1Panel"
|
||||
RestoreNoSuchFile: "Файлы для отката не найдены"
|
||||
RestoreStep1: "(1/5) Начинаем откат сервиса и данных 1Panel из каталога {{ .name }}..."
|
||||
|
||||
@@ -201,6 +201,7 @@ AppVersionExist: "Sürüm zaten mevcut"
|
||||
AppCreateSuccessful: "Oluşturma başarılı"
|
||||
AppWriteErr: "Dosya {{ .name }} yazma başarısız {{ .err }}"
|
||||
SudoHelper: "Lütfen {{ .cmd }} kullanın veya root kullanıcısına geçin"
|
||||
UsernameNeed: "Enterprise sürümü --username belirtmelidir"
|
||||
ListenIPCommands: "Dinleme IP'sini değiştir"
|
||||
ListenIPv4: "IPv4'te dinle"
|
||||
ListenIPv6: "IPv6'da dinle"
|
||||
@@ -212,6 +213,12 @@ ResetEntrance: "1Panel güvenli girişi iptal et"
|
||||
ResetIPs: "1Panel yetkili IP kısıtlamalarını iptal et"
|
||||
ResetDomain: "1Panel alan adı bağlamasını iptal et"
|
||||
ResetPasskey: "1Panel passkey'lerini sıfırla"
|
||||
UserList: "1Panel kullanıcı listesini getir"
|
||||
UserTableName: "Ad"
|
||||
UserTableMFAStatus: "MFA Durumu"
|
||||
UserTableSuperAdmin: "Süper Yönetici"
|
||||
UserTableCreatedAt: "Oluşturulma"
|
||||
UserEmptyList: "Kullanıcı bulunamadı"
|
||||
RestoreCommands: "1Panel servisini ve verilerini geri al"
|
||||
RestoreNoSuchFile: "Rollback için dosya bulunamadı"
|
||||
RestoreStep1: "(1/5) {{ .name }} dizininden 1Panel hizmeti ve verileri geri alınıyor..."
|
||||
|
||||
@@ -204,6 +204,7 @@ AppVersionExist: "版本已存在!"
|
||||
AppCreateSuccessful: "建立成功!"
|
||||
AppWriteErr: "檔案 {{ .name }} 寫入失敗 {{ .err }}"
|
||||
SudoHelper: "請使用 {{ .cmd }} 或切換到 root 使用者"
|
||||
UsernameNeed: "企業版必須指定 --username"
|
||||
ListenIPCommands: "切換監聽 IP"
|
||||
ListenIPv4: "監聽 IPv4"
|
||||
ListenIPv6: "監聽 IPv6"
|
||||
@@ -215,6 +216,12 @@ ResetEntrance: "取消 1Panel 安全入口"
|
||||
ResetIPs: "取消 1Panel 授權 IP 限制"
|
||||
ResetDomain: "取消 1Panel 存取網域綁定"
|
||||
ResetPasskey: "清空 1Panel 通行密鑰"
|
||||
UserList: "獲取 1Panel 使用者列表"
|
||||
UserTableName: "名稱"
|
||||
UserTableMFAStatus: "MFA 狀態"
|
||||
UserTableSuperAdmin: "超級管理員"
|
||||
UserTableCreatedAt: "建立時間"
|
||||
UserEmptyList: "暫無使用者"
|
||||
RestoreCommands: "回滾 1Panel 服務及資料"
|
||||
RestoreNoSuchFile: "暫無可回滾檔案"
|
||||
RestoreStep1: "(1/5)開始從 {{ .name }} 目錄回滾 1Panel 服務及資料... "
|
||||
|
||||
@@ -209,6 +209,7 @@ AppVersionExist: "版本已存在!"
|
||||
AppCreateSuccessful: "创建成功!"
|
||||
AppWriteErr: "文件 {{ .name }} 写入失败 {{ .err }}"
|
||||
SudoHelper: "请使用 {{ .cmd }} 或切换到 root 用户"
|
||||
UsernameNeed: "企业版必须指定 --username"
|
||||
ListenIPCommands: "切换监听 IP"
|
||||
ListenIPv4: "监听 IPv4"
|
||||
ListenIPv6: "监听 IPv6"
|
||||
@@ -220,6 +221,12 @@ ResetEntrance: "取消 1Panel 安全入口"
|
||||
ResetIPs: "取消 1Panel 授权 IP 限制"
|
||||
ResetDomain: "取消 1Panel 访问域名绑定"
|
||||
ResetPasskey: "清空 1Panel 通行密钥"
|
||||
UserList: "获取 1Panel 用户列表"
|
||||
UserTableName: "名称"
|
||||
UserTableMFAStatus: "MFA 状态"
|
||||
UserTableSuperAdmin: "超级管理员"
|
||||
UserTableCreatedAt: "创建时间"
|
||||
UserEmptyList: "暂无用户"
|
||||
RestoreCommands: "回滚 1Panel 服务及数据"
|
||||
RestoreNoSuchFile: "暂无可回滚文件"
|
||||
RestoreStep1: "(1/5)开始从 {{ .name }} 目录回滚 1Panel 服务及数据... "
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/app/api/v2/helper"
|
||||
"github.com/1Panel-dev/1Panel/core/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/security"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -32,7 +33,7 @@ func BindDomain() gin.HandlerFunc {
|
||||
}
|
||||
|
||||
if domains != bindDomain {
|
||||
code := LoadErrCode()
|
||||
code := security.LoadErrCode()
|
||||
helper.ErrWithHtml(c, code, "err_domain")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/app/repo"
|
||||
)
|
||||
|
||||
func LoadErrCode() int {
|
||||
settingRepo := repo.NewISettingRepo()
|
||||
codeVal, err := settingRepo.GetValueByKey("NoAuthSetting")
|
||||
if err != nil {
|
||||
return 500
|
||||
}
|
||||
|
||||
switch codeVal {
|
||||
case "400":
|
||||
return http.StatusBadRequest
|
||||
case "401":
|
||||
return http.StatusUnauthorized
|
||||
case "403":
|
||||
return http.StatusForbidden
|
||||
case "404":
|
||||
return http.StatusNotFound
|
||||
case "408":
|
||||
return http.StatusRequestTimeout
|
||||
case "416":
|
||||
return http.StatusRequestedRangeNotSatisfiable
|
||||
case "500":
|
||||
return http.StatusInternalServerError
|
||||
case "444":
|
||||
return 444
|
||||
default:
|
||||
return http.StatusOK
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/core/utils/common"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/app/api/v2/helper"
|
||||
"github.com/1Panel-dev/1Panel/core/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/security"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@@ -43,7 +44,7 @@ func WhiteAllow() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
}
|
||||
code := LoadErrCode()
|
||||
code := security.LoadErrCode()
|
||||
helper.ErrWithHtml(c, code, "err_ip_limit")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@ import (
|
||||
|
||||
func PasswordExpired() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if !strings.HasPrefix(c.Request.URL.Path, "/api/v2/") {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
if strings.HasPrefix(c.Request.URL.Path, "/api/v2/core/auth") ||
|
||||
c.Request.URL.Path == "/api/v2/core/settings/search" ||
|
||||
c.Request.URL.Path == "/api/v2/core/settings/search/base" ||
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/app/repo"
|
||||
@@ -41,7 +40,9 @@ func HandleNotRoute(c *gin.Context) bool {
|
||||
}
|
||||
|
||||
func CheckSecurity(c *gin.Context) bool {
|
||||
if !checkEntrance(c) && !checkSession(c) {
|
||||
authService := service.NewIAuthService()
|
||||
entrance := authService.GetSecurityEntrance()
|
||||
if entrance != "" && !checkEntrance(c) && !checkSession(c) {
|
||||
HandleNotSecurity(c, "")
|
||||
return false
|
||||
}
|
||||
@@ -95,18 +96,14 @@ func checkEntrance(c *gin.Context) bool {
|
||||
}
|
||||
|
||||
func HandleNotSecurity(c *gin.Context, resType string) {
|
||||
resPage, err := service.NewIAuthService().GetResponsePage()
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "Internal Server Error")
|
||||
return
|
||||
}
|
||||
if resPage == "444" {
|
||||
code := LoadErrCode()
|
||||
if code == 444 {
|
||||
CloseDirectly(c)
|
||||
return
|
||||
}
|
||||
|
||||
file := fmt.Sprintf("html/%s.html", resPage)
|
||||
if resPage == "200" && resType != "" {
|
||||
file := fmt.Sprintf("html/%d.html", code)
|
||||
if code == http.StatusOK && resType != "" {
|
||||
file = fmt.Sprintf("html/200_%s.html", resType)
|
||||
}
|
||||
data, err := res.ErrorMsg.ReadFile(file)
|
||||
@@ -114,12 +111,36 @@ func HandleNotSecurity(c *gin.Context, resType string) {
|
||||
c.String(http.StatusInternalServerError, "Internal Server Error")
|
||||
return
|
||||
}
|
||||
statusCode, err := strconv.Atoi(resPage)
|
||||
c.Data(code, "text/html; charset=utf-8", data)
|
||||
}
|
||||
|
||||
func LoadErrCode() int {
|
||||
settingRepo := repo.NewISettingRepo()
|
||||
codeVal, err := settingRepo.GetValueByKey("NoAuthSetting")
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "Internal Server Error")
|
||||
return
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
|
||||
switch codeVal {
|
||||
case "400":
|
||||
return http.StatusBadRequest
|
||||
case "401":
|
||||
return http.StatusUnauthorized
|
||||
case "403":
|
||||
return http.StatusForbidden
|
||||
case "404":
|
||||
return http.StatusNotFound
|
||||
case "408":
|
||||
return http.StatusRequestTimeout
|
||||
case "416":
|
||||
return http.StatusRequestedRangeNotSatisfiable
|
||||
case "500":
|
||||
return http.StatusInternalServerError
|
||||
case "444":
|
||||
return 444
|
||||
default:
|
||||
return http.StatusOK
|
||||
}
|
||||
c.Data(statusCode, "text/html; charset=utf-8", data)
|
||||
}
|
||||
|
||||
func IsFrontendPath(path string) bool {
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
import { routerToNameWithQuery, routerToPathWithQuery } from '@/utils/router';
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { hasPermissionMetaAccess } from '@/utils/rbac';
|
||||
import { hasPermissionMetaAccess, hasRouteAccess } from '@/utils/rbac';
|
||||
|
||||
defineOptions({ name: 'RouterButton' });
|
||||
|
||||
@@ -37,11 +37,20 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
const buttonArray = computed(() => {
|
||||
return props.buttons.filter((button) => hasPermissionMetaAccess(button.permission));
|
||||
return props.buttons.filter((button) => {
|
||||
if (!hasPermissionMetaAccess(button.permission)) {
|
||||
return false;
|
||||
}
|
||||
if (button.path || button.name) {
|
||||
const route = router.resolve(button.path ? { path: button.path } : { name: button.name });
|
||||
return route.matched.length === 0 || hasRouteAccess(route);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
const activeName = ref('');
|
||||
|
||||
const handleChange = (label: string) => {
|
||||
|
||||
@@ -11,6 +11,7 @@ const axiosCanceler = new AxiosCanceler();
|
||||
|
||||
let isRedirecting = false;
|
||||
const enterpriseLicenseCheckWhiteList = ['EnterpriseLicenseRequired', 'entrance', 'login', 'Expired'];
|
||||
const noLoginWhiteList = ['entrance', 'login', 'file-share', '404', 'Expired'];
|
||||
|
||||
const clearLicenseStatus = () => {
|
||||
const { isEnterpriseLicenseLoaded, isEnterpriseLicensed } = useGlobalStore();
|
||||
@@ -33,10 +34,31 @@ router.beforeEach(async (to, from, next) => {
|
||||
if (!isLogin.value) {
|
||||
clearLoginStatus();
|
||||
}
|
||||
if (to.name !== 'entrance' && !isLogin.value) {
|
||||
if (!isLogin.value && !noLoginWhiteList.includes(String(to.name))) {
|
||||
next(
|
||||
entrance.value
|
||||
? {
|
||||
name: 'entrance',
|
||||
params: { code: entrance.value },
|
||||
}
|
||||
: {
|
||||
name: 'login',
|
||||
},
|
||||
);
|
||||
NProgress.done();
|
||||
return;
|
||||
}
|
||||
if (to.name === 'login' && !isLogin.value && entrance.value) {
|
||||
next({
|
||||
name: 'entrance',
|
||||
params: to.params,
|
||||
params: { code: entrance.value },
|
||||
});
|
||||
NProgress.done();
|
||||
return;
|
||||
}
|
||||
if (to.name === 'login' && isLogin.value) {
|
||||
next({
|
||||
name: 'home',
|
||||
});
|
||||
NProgress.done();
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user