| 100 | } |
| 101 | |
| 102 | func (u *UserRecord) PasswordMatches(input string) bool { |
| 103 | |
| 104 | // Try bcrypt first (new format). |
| 105 | if err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(input)); err == nil { |
| 106 | return true |
| 107 | } |
| 108 | |
| 109 | // Migration: check if stored password is old unsalted SHA256 format. |
| 110 | if u.Password == util.Hash(input) { |
| 111 | // Re-hash with bcrypt so subsequent logins use the secure path. |
| 112 | if hash, err := bcrypt.GenerateFromPassword([]byte(input), bcrypt.DefaultCost); err == nil { |
| 113 | u.Password = string(hash) |
| 114 | } |
| 115 | return true |
| 116 | } |
| 117 | |
| 118 | // Special case for new setups before things get reset |
| 119 | if u.HasPlaintextPassword() && u.Password == input { |
| 120 | return true |
| 121 | } |
| 122 | |
| 123 | // No plaintext fallback. No hash-of-hash bypass. |
| 124 | return false |
| 125 | } |
| 126 | |
| 127 | func (u *UserRecord) AddCommandAlias(input string, output string) (addedAlias string, deletedAlias string) { |
| 128 | |