Skip to content
Open
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
74 changes: 73 additions & 1 deletion core/app/api/v2/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package v2

import (
"encoding/base64"
"github.com/1Panel-dev/1Panel/core/utils/common"
"net/http"
"os"
"path"

Expand All @@ -12,6 +12,7 @@ import (
"github.com/1Panel-dev/1Panel/core/constant"
"github.com/1Panel-dev/1Panel/core/global"
"github.com/1Panel-dev/1Panel/core/utils/captcha"
"github.com/1Panel-dev/1Panel/core/utils/common"
"github.com/gin-gonic/gin"
)

Expand Down Expand Up @@ -100,6 +101,61 @@ func (b *BaseApi) MFALogin(c *gin.Context) {
helper.SuccessWithData(c, user)
}

// @Tags Auth
// @Summary User login with passkey
// @Success 200 {object} dto.PasskeyBeginResponse
// @Router /core/auth/passkey/begin [post]
func (b *BaseApi) PasskeyBeginLogin(c *gin.Context) {
entrance := loadEntranceFromRequest(c)
res, msgKey, err := authService.PasskeyBeginLogin(c, entrance)
if msgKey != "" {
if msgKey == "ErrEntrance" {
helper.BadAuth(c, msgKey, err)
return
}
if msgKey == "ErrPasskeyNotConfigured" {
helper.ErrorWithDetail(c, http.StatusNotFound, msgKey, err)
return
}
helper.ErrorWithDetail(c, http.StatusBadRequest, msgKey, err)
return
}
if err != nil {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, res)
}

// @Tags Auth
// @Summary User login with passkey
// @Success 200 {object} dto.UserLoginInfo
// @Router /core/auth/passkey/finish [post]
func (b *BaseApi) PasskeyFinishLogin(c *gin.Context) {
sessionID := c.GetHeader("Passkey-Session")
entrance := loadEntranceFromRequest(c)
user, msgKey, err := authService.PasskeyFinishLogin(c, sessionID, entrance)
go saveLoginLogs(c, err)
if msgKey == "ErrAuth" || msgKey == "ErrEntrance" {
if msgKey == "ErrAuth" {
global.IPTracker.SetNeedCaptcha(common.GetRealClientIP(c))
}
helper.BadAuth(c, msgKey, err)
return
}
if msgKey != "" {
helper.ErrorWithDetail(c, http.StatusBadRequest, msgKey, err)
return
}
if err != nil {
global.IPTracker.SetNeedCaptcha(common.GetRealClientIP(c))
helper.InternalServer(c, err)
return
}
global.IPTracker.Clear(common.GetRealClientIP(c))
helper.SuccessWithData(c, user)
}

// @Tags Auth
// @Summary User logout
// @Success 200
Expand Down Expand Up @@ -164,6 +220,7 @@ func (b *BaseApi) GetLoginSetting(c *gin.Context) {
Theme: settingInfo.Theme,
NeedCaptcha: needCaptcha,
}
res.PasskeySetting = authService.PasskeyStatus(c)
helper.SuccessWithData(c, res)
}

Expand All @@ -179,3 +236,18 @@ func saveLoginLogs(c *gin.Context, err error) {
logs.Agent = c.GetHeader("User-Agent")
_ = logService.CreateLoginLog(logs)
}

func loadEntranceFromRequest(c *gin.Context) string {
entranceItem := c.Request.Header.Get("EntranceCode")
var entrance []byte
if len(entranceItem) != 0 {
entrance, _ = base64.StdEncoding.DecodeString(entranceItem)
}
if len(entrance) == 0 {
cookieValue, err := c.Cookie("SecurityEntrance")
if err == nil {
entrance, _ = base64.StdEncoding.DecodeString(cookieValue)
}
}
return string(entrance)
}
80 changes: 80 additions & 0 deletions core/app/api/v2/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,86 @@ func (b *BaseApi) MFABind(c *gin.Context) {
helper.Success(c)
}

// @Tags System Setting
// @Summary Begin passkey registration
// @Accept json
// @Param request body dto.PasskeyRegisterRequest true "request"
// @Success 200 {object} dto.PasskeyBeginResponse
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /core/settings/passkey/register/begin [post]
func (b *BaseApi) PasskeyRegisterBegin(c *gin.Context) {
var req dto.PasskeyRegisterRequest
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
res, msgKey, err := authService.PasskeyBeginRegister(c, req.Name)
if msgKey != "" {
helper.ErrorWithDetail(c, http.StatusBadRequest, msgKey, err)
return
}
if err != nil {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, res)
}

// @Tags System Setting
// @Summary Finish passkey registration
// @Accept json
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /core/settings/passkey/register/finish [post]
func (b *BaseApi) PasskeyRegisterFinish(c *gin.Context) {
sessionID := c.GetHeader("Passkey-Session")
msgKey, err := authService.PasskeyFinishRegister(c, sessionID)
if msgKey != "" {
helper.ErrorWithDetail(c, http.StatusBadRequest, msgKey, err)
return
}
if err != nil {
helper.InternalServer(c, err)
return
}
helper.Success(c)
}

// @Tags System Setting
// @Summary List passkeys
// @Success 200 {array} dto.PasskeyInfo
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /core/settings/passkey/list [get]
func (b *BaseApi) PasskeyList(c *gin.Context) {
list, err := authService.PasskeyList()
if err != nil {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, list)
}

// @Tags System Setting
// @Summary Delete passkey
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /core/settings/passkey/{id} [delete]
func (b *BaseApi) PasskeyDelete(c *gin.Context) {
id := c.Param("id")
if id == "" {
helper.BadRequest(c, errors.New("passkey id is required"))
return
}
if err := authService.PasskeyDelete(id); err != nil {
helper.InternalServer(c, err)
return
}
helper.Success(c)
}

func (b *BaseApi) ReloadSSL(c *gin.Context) {
clientIP := c.ClientIP()
if clientIP != "127.0.0.1" {
Expand Down
5 changes: 5 additions & 0 deletions core/app/dto/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ type UserLoginInfo struct {
MfaStatus string `json:"mfaStatus"`
}

type PasskeyBeginResponse struct {
SessionID string `json:"sessionId"`
PublicKey interface{} `json:"publicKey"`
}

type MfaRequest struct {
Title string `json:"title" validate:"required"`
Interval int `json:"interval" validate:"required"`
Expand Down
12 changes: 12 additions & 0 deletions core/app/dto/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,4 +250,16 @@ type LoginSetting struct {
PanelName string `json:"panelName"`
Theme string `json:"theme"`
NeedCaptcha bool `json:"needCaptcha"`
PasskeySetting bool `json:"passkeySetting"`
}

type PasskeyRegisterRequest struct {
Name string `json:"name" validate:"required"`
}

type PasskeyInfo struct {
ID string `json:"id"`
Name string `json:"name"`
CreatedAt string `json:"createdAt"`
LastUsedAt string `json:"lastUsedAt"`
}
Loading
Loading