fix: improve security entrance and user commands (#12770)

This commit is contained in:
ssongliu
2026-05-19 17:30:50 +08:00
committed by zhengkunwang223
parent 9d3313fe11
commit e7578a9fc5
20 changed files with 405 additions and 63 deletions

View File

@@ -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

View File

@@ -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
View 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
}

View File

@@ -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..."

View File

@@ -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 }}..."

View File

@@ -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 のサービスとデータのロールバックを開始しています..."

View File

@@ -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 서비스와 데이터의 롤백을 시작합니다..."

View File

@@ -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 }}..."

View File

@@ -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 }}..."

View File

@@ -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 }}..."

View File

@@ -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..."

View File

@@ -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 服務及資料... "

View File

@@ -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 服务及数据... "

View File

@@ -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
}

View File

@@ -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
}
}

View File

@@ -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")
}
}

View File

@@ -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" ||

View File

@@ -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 {

View File

@@ -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) => {

View File

@@ -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;