Junie: add TOTP authentication

This commit is contained in:
2025-06-06 11:35:49 -07:00
parent 13d009bf4f
commit 396214739e
10 changed files with 439 additions and 12 deletions

View File

@@ -17,12 +17,13 @@ const (
)
type User struct {
ID string
Created int64
User string
Password []byte
Salt []byte
Roles []string
ID string
Created int64
User string
Password []byte
Salt []byte
TOTPSecret string
Roles []string
}
// HasRole checks if the user has a specific role
@@ -49,6 +50,7 @@ type Login struct {
User string `json:"user"`
Password string `json:"password,omitzero"`
Token string `json:"token,omitzero"`
TOTPCode string `json:"totp_code,omitzero"`
}
func derive(password string, salt []byte) ([]byte, error) {
@@ -69,6 +71,18 @@ func (u *User) Check(login *Login) bool {
return false
}
// If TOTP is enabled for the user, validate the TOTP code
if u.TOTPSecret != "" && login.TOTPCode != "" {
// Use the ValidateTOTPCode method to validate the TOTP code
valid, err := u.ValidateTOTPCode(login.TOTPCode)
if err != nil || !valid {
return false
}
} else if u.TOTPSecret != "" && login.TOTPCode == "" {
// TOTP is enabled but no code was provided
return false
}
return true
}
@@ -97,3 +111,31 @@ func (u *User) Register(login *Login) error {
u.Created = time.Now().Unix()
return nil
}
// GenerateTOTPSecret generates a new TOTP secret for the user
func (u *User) GenerateTOTPSecret() (string, error) {
// Generate a random secret
secret, err := GenerateRandomBase32(20) // 20 bytes = 160 bits
if err != nil {
return "", fmt.Errorf("failed to generate TOTP secret: %w", err)
}
u.TOTPSecret = secret
return u.TOTPSecret, nil
}
// ValidateTOTPCode validates a TOTP code against the user's TOTP secret
func (u *User) ValidateTOTPCode(code string) (bool, error) {
if u.TOTPSecret == "" {
return false, errors.New("TOTP not enabled for user")
}
// Use the twofactor package to validate the code
valid := ValidateTOTP(u.TOTPSecret, code)
return valid, nil
}
// HasTOTP returns true if TOTP is enabled for the user
func (u *User) HasTOTP() bool {
return u.TOTPSecret != ""
}