mirror of https://github.com/Xhofe/alist
218 lines
4.9 KiB
Go
218 lines
4.9 KiB
Go
![]() |
package handles
|
||
|
|
||
|
import (
|
||
|
"encoding/base64"
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
|
||
|
"github.com/alist-org/alist/v3/internal/authn"
|
||
|
"github.com/alist-org/alist/v3/internal/conf"
|
||
|
"github.com/alist-org/alist/v3/internal/db"
|
||
|
"github.com/alist-org/alist/v3/internal/model"
|
||
|
"github.com/alist-org/alist/v3/internal/op"
|
||
|
"github.com/alist-org/alist/v3/internal/setting"
|
||
|
"github.com/alist-org/alist/v3/server/common"
|
||
|
"github.com/gin-gonic/gin"
|
||
|
"github.com/go-webauthn/webauthn/webauthn"
|
||
|
)
|
||
|
|
||
|
func BeginAuthnLogin(c *gin.Context) {
|
||
|
enabled := setting.GetBool(conf.WebauthnLoginEnabled)
|
||
|
if !enabled {
|
||
|
common.ErrorStrResp(c, "WebAuthn is not enabled", 403)
|
||
|
return
|
||
|
}
|
||
|
username := c.Query("username")
|
||
|
if username == "" {
|
||
|
common.ErrorStrResp(c, "empty or no username provided", 400)
|
||
|
return
|
||
|
}
|
||
|
user, err := db.GetUserByName(username)
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
return
|
||
|
}
|
||
|
authnInstance, err := authn.NewAuthnInstance(c.Request)
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
options, sessionData, err := authnInstance.BeginLogin(user)
|
||
|
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
return
|
||
|
}
|
||
|
val, err := json.Marshal(sessionData)
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
return
|
||
|
}
|
||
|
common.SuccessResp(c, gin.H{
|
||
|
"options": options,
|
||
|
"session": val,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func FinishAuthnLogin(c *gin.Context) {
|
||
|
enabled := setting.GetBool(conf.WebauthnLoginEnabled)
|
||
|
if !enabled {
|
||
|
common.ErrorStrResp(c, "WebAuthn is not enabled", 403)
|
||
|
return
|
||
|
}
|
||
|
username := c.Query("username")
|
||
|
user, err := db.GetUserByName(username)
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
sessionDataString := c.GetHeader("session")
|
||
|
|
||
|
authnInstance, err := authn.NewAuthnInstance(c.Request)
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
return
|
||
|
}
|
||
|
sessionDataBytes, err := base64.StdEncoding.DecodeString(sessionDataString)
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var sessionData webauthn.SessionData
|
||
|
if err := json.Unmarshal(sessionDataBytes, &sessionData); err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
_, err = authnInstance.FinishLogin(user, sessionData, c.Request)
|
||
|
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
token, err := common.GenerateToken(user.Username)
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400, true)
|
||
|
return
|
||
|
}
|
||
|
common.SuccessResp(c, gin.H{"token": token})
|
||
|
}
|
||
|
|
||
|
func BeginAuthnRegistration(c *gin.Context) {
|
||
|
enabled := setting.GetBool(conf.WebauthnLoginEnabled)
|
||
|
if !enabled {
|
||
|
common.ErrorStrResp(c, "WebAuthn is not enabled", 403)
|
||
|
return
|
||
|
}
|
||
|
user := c.MustGet("user").(*model.User)
|
||
|
|
||
|
authnInstance, err := authn.NewAuthnInstance(c.Request)
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
}
|
||
|
|
||
|
options, sessionData, err := authnInstance.BeginRegistration(user)
|
||
|
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
}
|
||
|
|
||
|
val, err := json.Marshal(sessionData)
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
}
|
||
|
|
||
|
common.SuccessResp(c, gin.H{
|
||
|
"options": options,
|
||
|
"session": val,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func FinishAuthnRegistration(c *gin.Context) {
|
||
|
enabled := setting.GetBool(conf.WebauthnLoginEnabled)
|
||
|
if !enabled {
|
||
|
common.ErrorStrResp(c, "WebAuthn is not enabled", 403)
|
||
|
return
|
||
|
}
|
||
|
user := c.MustGet("user").(*model.User)
|
||
|
sessionDataString := c.GetHeader("Session")
|
||
|
|
||
|
authnInstance, err := authn.NewAuthnInstance(c.Request)
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
sessionDataBytes, err := base64.StdEncoding.DecodeString(sessionDataString)
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var sessionData webauthn.SessionData
|
||
|
if err := json.Unmarshal(sessionDataBytes, &sessionData); err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
credential, err := authnInstance.FinishRegistration(user, sessionData, c.Request)
|
||
|
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
return
|
||
|
}
|
||
|
err = db.RegisterAuthn(user, credential)
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
return
|
||
|
}
|
||
|
err = op.DelUserCache(user.Username)
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
return
|
||
|
}
|
||
|
common.SuccessResp(c, "Registered Successfully")
|
||
|
}
|
||
|
|
||
|
func DeleteAuthnLogin(c *gin.Context) {
|
||
|
user := c.MustGet("user").(*model.User)
|
||
|
type DeleteAuthnReq struct {
|
||
|
ID string `json:"id"`
|
||
|
}
|
||
|
var req DeleteAuthnReq
|
||
|
err := c.ShouldBind(&req)
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
return
|
||
|
}
|
||
|
err = db.RemoveAuthn(user, req.ID)
|
||
|
err = op.DelUserCache(user.Username)
|
||
|
if err != nil {
|
||
|
common.ErrorResp(c, err, 400)
|
||
|
return
|
||
|
}
|
||
|
common.SuccessResp(c, "Deleted Successfully")
|
||
|
}
|
||
|
|
||
|
func GetAuthnCredentials(c *gin.Context) {
|
||
|
type WebAuthnCredentials struct {
|
||
|
ID []byte `json:"id"`
|
||
|
FingerPrint string `json:"fingerprint"`
|
||
|
}
|
||
|
user := c.MustGet("user").(*model.User)
|
||
|
credentials := user.WebAuthnCredentials()
|
||
|
res := make([]WebAuthnCredentials, 0, len(credentials))
|
||
|
for _, v := range credentials {
|
||
|
credential := WebAuthnCredentials{
|
||
|
ID: v.ID,
|
||
|
FingerPrint: fmt.Sprintf("% X", v.Authenticator.AAGUID),
|
||
|
}
|
||
|
res = append(res, credential)
|
||
|
}
|
||
|
common.SuccessResp(c, res)
|
||
|
}
|