mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-11 02:15:48 +02:00
feat: login via passkey
This commit is contained in:
parent
44c3180df7
commit
bdfbbd0e8f
37 changed files with 1529 additions and 643 deletions
4
internal/cache/cache.go
vendored
4
internal/cache/cache.go
vendored
|
@ -29,3 +29,7 @@ func Set(key interface{}, value interface{}, ttl time.Duration) {
|
|||
func Get(key interface{}) (value interface{}, ok bool) {
|
||||
return cache.Get(key)
|
||||
}
|
||||
|
||||
func Del(key interface{}) {
|
||||
cache.Del(key)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/0xJacky/Nginx-UI/internal/cluster"
|
||||
"github.com/0xJacky/Nginx-UI/internal/cron"
|
||||
"github.com/0xJacky/Nginx-UI/internal/logger"
|
||||
"github.com/0xJacky/Nginx-UI/internal/passkey"
|
||||
"github.com/0xJacky/Nginx-UI/internal/validation"
|
||||
"github.com/0xJacky/Nginx-UI/model"
|
||||
"github.com/0xJacky/Nginx-UI/query"
|
||||
|
@ -50,6 +51,7 @@ func InitAfterDatabase() {
|
|||
cron.InitCronJobs,
|
||||
cluster.RegisterPredefinedNodes,
|
||||
analytic.RetrieveNodesStatus,
|
||||
passkey.Init,
|
||||
}
|
||||
|
||||
for _, v := range syncs {
|
||||
|
|
|
@ -51,7 +51,7 @@ func registerPredefinedUser() {
|
|||
logger.Fatal(err)
|
||||
}
|
||||
|
||||
u := query.Auth
|
||||
u := query.User
|
||||
|
||||
_, err = u.First()
|
||||
|
||||
|
@ -63,7 +63,7 @@ func registerPredefinedUser() {
|
|||
// Create a new user with the predefined name and password
|
||||
pwd, _ := bcrypt.GenerateFromPassword([]byte(pUser.Password), bcrypt.DefaultCost)
|
||||
|
||||
err = u.Create(&model.Auth{
|
||||
err = u.Create(&model.User{
|
||||
Name: pUser.Name,
|
||||
Password: string(pwd),
|
||||
})
|
||||
|
|
|
@ -14,7 +14,7 @@ func RequireSecureSession() gin.HandlerFunc {
|
|||
c.Next()
|
||||
return
|
||||
}
|
||||
cUser := u.(*model.Auth)
|
||||
cUser := u.(*model.User)
|
||||
if !cUser.EnabledOTP() {
|
||||
c.Next()
|
||||
return
|
||||
|
|
46
internal/passkey/webauthn.go
Normal file
46
internal/passkey/webauthn.go
Normal file
|
@ -0,0 +1,46 @@
|
|||
package passkey
|
||||
|
||||
import (
|
||||
"github.com/0xJacky/Nginx-UI/internal/logger"
|
||||
"github.com/0xJacky/Nginx-UI/settings"
|
||||
"github.com/go-webauthn/webauthn/protocol"
|
||||
"github.com/go-webauthn/webauthn/webauthn"
|
||||
)
|
||||
|
||||
var instance *webauthn.WebAuthn
|
||||
|
||||
func Init() {
|
||||
options := &settings.WebAuthnSettings
|
||||
|
||||
if !Enabled() {
|
||||
logger.Debug("WebAuthn settings are not configured")
|
||||
return
|
||||
}
|
||||
requireResidentKey := true
|
||||
var err error
|
||||
instance, err = webauthn.New(&webauthn.Config{
|
||||
RPDisplayName: options.RPDisplayName,
|
||||
RPID: options.RPID,
|
||||
RPOrigins: options.RPOrigins,
|
||||
AuthenticatorSelection: protocol.AuthenticatorSelection{
|
||||
RequireResidentKey: &requireResidentKey,
|
||||
UserVerification: "required",
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Enabled() bool {
|
||||
options := &settings.WebAuthnSettings
|
||||
if options.RPDisplayName == "" || options.RPID == "" || len(options.RPOrigins) == 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func GetInstance() *webauthn.WebAuthn {
|
||||
return instance
|
||||
}
|
|
@ -14,8 +14,8 @@ var (
|
|||
ErrUserBanned = errors.New("user banned")
|
||||
)
|
||||
|
||||
func Login(name string, password string) (user *model.Auth, err error) {
|
||||
u := query.Auth
|
||||
func Login(name string, password string) (user *model.User, err error) {
|
||||
u := query.User
|
||||
|
||||
user, err = u.Where(u.Name.Eq(name)).First()
|
||||
if err != nil {
|
||||
|
|
|
@ -19,7 +19,7 @@ var (
|
|||
ErrRecoveryCode = errors.New("invalid recovery code")
|
||||
)
|
||||
|
||||
func VerifyOTP(user *model.Auth, otp, recoveryCode string) (err error) {
|
||||
func VerifyOTP(user *model.User, otp, recoveryCode string) (err error) {
|
||||
if otp != "" {
|
||||
decrypted, err := crypto.AesDecrypt(user.OTPSecret)
|
||||
if err != nil {
|
||||
|
|
|
@ -26,9 +26,9 @@ func BuildCacheTokenKey(token string) string {
|
|||
return sb.String()
|
||||
}
|
||||
|
||||
func GetUser(name string) (user *model.Auth, err error) {
|
||||
func GetUser(name string) (user *model.User, err error) {
|
||||
db := model.UseDB()
|
||||
user = &model.Auth{}
|
||||
user = &model.User{}
|
||||
err = db.Where("name", name).First(user).Error
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -41,7 +41,7 @@ func DeleteToken(token string) {
|
|||
_, _ = q.Where(q.Token.Eq(token)).Delete()
|
||||
}
|
||||
|
||||
func GetTokenUser(token string) (*model.Auth, bool) {
|
||||
func GetTokenUser(token string) (*model.User, bool) {
|
||||
q := query.AuthToken
|
||||
authToken, err := q.Where(q.Token.Eq(token)).First()
|
||||
if err != nil {
|
||||
|
@ -53,12 +53,12 @@ func GetTokenUser(token string) (*model.Auth, bool) {
|
|||
return nil, false
|
||||
}
|
||||
|
||||
u := query.Auth
|
||||
u := query.User
|
||||
user, err := u.FirstByID(authToken.UserID)
|
||||
return user, err == nil
|
||||
}
|
||||
|
||||
func GenerateJWT(user *model.Auth) (string, error) {
|
||||
func GenerateJWT(user *model.User) (string, error) {
|
||||
claims := JWTClaims{
|
||||
Name: user.Name,
|
||||
UserID: user.ID,
|
||||
|
@ -114,7 +114,7 @@ func ValidateJWT(token string) (claims *JWTClaims, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func CurrentUser(token string) (u *model.Auth, err error) {
|
||||
func CurrentUser(token string) (u *model.User, err error) {
|
||||
// validate token
|
||||
var claims *JWTClaims
|
||||
claims, err = ValidateJWT(token)
|
||||
|
@ -123,7 +123,7 @@ func CurrentUser(token string) (u *model.Auth, err error) {
|
|||
}
|
||||
|
||||
// get user by id
|
||||
user := query.Auth
|
||||
user := query.User
|
||||
u, err = user.FirstByID(claims.UserID)
|
||||
if err != nil {
|
||||
return
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue