mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
Pre-review snapshot of LiveKit migration changes including: - Permission computation fix (allow-wins semantics) - Timing-safe password comparison with dummy hash - Rate limiter window fix - Dev credential clearing for LiveKit - Voice leave/join broadcast improvements - Migration transaction wrapping - Chat edit/delete permission guards - TOTP verification endpoint - Embed regex injection fix
62 lines
2.0 KiB
Go
62 lines
2.0 KiB
Go
package auth
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
const (
|
|
bcryptCost = 12
|
|
minPassLen = 8
|
|
maxPassLen = 72 // bcrypt silently truncates beyond 72 bytes
|
|
)
|
|
|
|
// ErrPasswordTooShort is returned when the password is below the minimum length.
|
|
var ErrPasswordTooShort = errors.New("password must be at least 8 characters")
|
|
|
|
// ErrPasswordTooLong is returned when the password exceeds bcrypt's 72-byte limit.
|
|
var ErrPasswordTooLong = errors.New("password must not exceed 72 characters")
|
|
|
|
// HashPassword returns a bcrypt hash of password using cost 12.
|
|
func HashPassword(password string) (string, error) {
|
|
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcryptCost)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(hash), nil
|
|
}
|
|
|
|
// dummyHash is a pre-computed bcrypt hash used to prevent timing side-channels
|
|
// when the user does not exist. Comparing against this dummy ensures that
|
|
// CheckPassword takes roughly constant time regardless of whether a valid hash
|
|
// was supplied.
|
|
var dummyHash, _ = bcrypt.GenerateFromPassword([]byte("dummy-timing-pad"), bcryptCost)
|
|
|
|
// CheckPassword reports whether password matches hash. Returns false on any
|
|
// error, including an empty or malformed hash. When hash is empty (user does
|
|
// not exist), a dummy bcrypt comparison is performed to prevent timing-based
|
|
// username enumeration.
|
|
func CheckPassword(hash, password string) bool {
|
|
if hash == "" {
|
|
// Perform a dummy comparison so the response time is indistinguishable
|
|
// from a real check, preventing timing-based username enumeration.
|
|
bcrypt.CompareHashAndPassword(dummyHash, []byte(password)) //nolint:errcheck
|
|
return false
|
|
}
|
|
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
|
return err == nil
|
|
}
|
|
|
|
// ValidatePasswordStrength returns an error if password fails strength
|
|
// requirements: minimum 8 characters, maximum 72 characters.
|
|
func ValidatePasswordStrength(password string) error {
|
|
if len(password) < minPassLen {
|
|
return ErrPasswordTooShort
|
|
}
|
|
if len(password) > maxPassLen {
|
|
return ErrPasswordTooLong
|
|
}
|
|
return nil
|
|
}
|