Add passkeys support + MFA (#341)
هذا الالتزام موجود في:
149
internal/db/webauth_credential.go
Normal file
149
internal/db/webauth_credential.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"github.com/go-webauthn/webauthn/webauthn"
|
||||
"time"
|
||||
)
|
||||
|
||||
type WebAuthnCredential struct {
|
||||
ID uint `gorm:"primaryKey"`
|
||||
Name string
|
||||
UserID uint
|
||||
User User
|
||||
CredentialID binaryData `gorm:"type:binary_data"`
|
||||
PublicKey binaryData `gorm:"type:binary_data"`
|
||||
AttestationType string
|
||||
AAGUID binaryData `gorm:"type:binary_data"`
|
||||
SignCount uint32
|
||||
CloneWarning bool
|
||||
FlagUserPresent bool
|
||||
FlagUserVerified bool
|
||||
FlagBackupEligible bool
|
||||
FlagBackupState bool
|
||||
CreatedAt int64
|
||||
LastUsedAt int64
|
||||
}
|
||||
|
||||
func (*WebAuthnCredential) TableName() string {
|
||||
return "webauthn"
|
||||
}
|
||||
|
||||
func GetAllWACredentialsForUser(userID uint) ([]webauthn.Credential, error) {
|
||||
var creds []WebAuthnCredential
|
||||
err := db.Where("user_id = ?", userID).Find(&creds).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webCreds := make([]webauthn.Credential, len(creds))
|
||||
for i, cred := range creds {
|
||||
webCreds[i] = webauthn.Credential{
|
||||
ID: cred.CredentialID,
|
||||
PublicKey: cred.PublicKey,
|
||||
AttestationType: cred.AttestationType,
|
||||
Authenticator: webauthn.Authenticator{
|
||||
AAGUID: cred.AAGUID,
|
||||
SignCount: cred.SignCount,
|
||||
CloneWarning: cred.CloneWarning,
|
||||
},
|
||||
Flags: webauthn.CredentialFlags{
|
||||
UserPresent: cred.FlagUserPresent,
|
||||
UserVerified: cred.FlagUserVerified,
|
||||
BackupEligible: cred.FlagBackupEligible,
|
||||
BackupState: cred.FlagBackupState,
|
||||
},
|
||||
}
|
||||
}
|
||||
return webCreds, nil
|
||||
}
|
||||
|
||||
func GetAllCredentialsForUser(userID uint) ([]WebAuthnCredential, error) {
|
||||
var creds []WebAuthnCredential
|
||||
err := db.Where("user_id = ?", userID).Find(&creds).Error
|
||||
return creds, err
|
||||
}
|
||||
|
||||
func GetUserByCredentialID(credID binaryData) (*User, error) {
|
||||
var credential WebAuthnCredential
|
||||
var err error
|
||||
|
||||
switch db.Dialector.Name() {
|
||||
case "postgres":
|
||||
hexCredID := hex.EncodeToString(credID)
|
||||
if err = db.Preload("User").Where("credential_id = decode(?, 'hex')", hexCredID).First(&credential).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "mysql":
|
||||
case "sqlite":
|
||||
hexCredID := hex.EncodeToString(credID)
|
||||
if err = db.Preload("User").Where("credential_id = unhex(?)", hexCredID).First(&credential).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &credential.User, err
|
||||
}
|
||||
|
||||
func GetCredentialByIDDB(id uint) (*WebAuthnCredential, error) {
|
||||
var cred WebAuthnCredential
|
||||
err := db.Where("id = ?", id).First(&cred).Error
|
||||
return &cred, err
|
||||
}
|
||||
|
||||
func GetCredentialByID(id binaryData) (*WebAuthnCredential, error) {
|
||||
var cred WebAuthnCredential
|
||||
var err error
|
||||
|
||||
switch db.Dialector.Name() {
|
||||
case "postgres":
|
||||
hexCredID := hex.EncodeToString(id)
|
||||
if err = db.Where("credential_id = decode(?, 'hex')", hexCredID).First(&cred).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "mysql":
|
||||
case "sqlite":
|
||||
hexCredID := hex.EncodeToString(id)
|
||||
if err = db.Where("credential_id = unhex(?)", hexCredID).First(&cred).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &cred, err
|
||||
}
|
||||
|
||||
func CreateFromCrendential(userID uint, name string, cred *webauthn.Credential) (*WebAuthnCredential, error) {
|
||||
credDb := &WebAuthnCredential{
|
||||
UserID: userID,
|
||||
Name: name,
|
||||
CredentialID: cred.ID,
|
||||
PublicKey: cred.PublicKey,
|
||||
AttestationType: cred.AttestationType,
|
||||
AAGUID: cred.Authenticator.AAGUID,
|
||||
SignCount: cred.Authenticator.SignCount,
|
||||
CloneWarning: cred.Authenticator.CloneWarning,
|
||||
FlagUserPresent: cred.Flags.UserPresent,
|
||||
FlagUserVerified: cred.Flags.UserVerified,
|
||||
FlagBackupEligible: cred.Flags.BackupEligible,
|
||||
FlagBackupState: cred.Flags.BackupState,
|
||||
}
|
||||
err := db.Create(credDb).Error
|
||||
return credDb, err
|
||||
}
|
||||
|
||||
func (w *WebAuthnCredential) UpdateSignCount() error {
|
||||
return db.Model(w).Update("sign_count", w.SignCount).Error
|
||||
}
|
||||
|
||||
func (w *WebAuthnCredential) UpdateLastUsedAt() error {
|
||||
return db.Model(w).Update("last_used_at", time.Now().Unix()).Error
|
||||
}
|
||||
|
||||
func (w *WebAuthnCredential) Delete() error {
|
||||
return db.Delete(w).Error
|
||||
}
|
||||
|
||||
// -- DTO -- //
|
||||
|
||||
type CrendentialDTO struct {
|
||||
PasskeyName string `json:"passkeyname" validate:"max=50"`
|
||||
}
|
||||
المرجع في مشكلة جديدة
حظر مستخدم