aboutsummaryrefslogtreecommitdiff
path: root/internal/player/password.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-09-19 03:15:59 -0400
committerhistoria <[not public]>2026-09-19 03:15:59 -0400
commit0e60567a7a0addb9421769ee7be7853bfa8788cb (patch)
tree7645112db0e4eae95b8a83c1e4f9aab38bede655 /internal/player/password.go
parentcc33072eced3d5460512c09c42ec4531c807d7af (diff)
downloadthehouseoficarus-0e60567a7a0addb9421769ee7be7853bfa8788cb.tar.gz
refactor: simplifcation, change how rooms are stored in player yaml, remove legacy code
Diffstat (limited to 'internal/player/password.go')
-rw-r--r--internal/player/password.go77
1 files changed, 25 insertions, 52 deletions
diff --git a/internal/player/password.go b/internal/player/password.go
index de5fe5f..706ef45 100644
--- a/internal/player/password.go
+++ b/internal/player/password.go
@@ -2,7 +2,6 @@ package player
import (
"crypto/rand"
- "crypto/sha256"
"crypto/subtle"
"encoding/base64"
"encoding/hex"
@@ -19,10 +18,8 @@ import (
//
// argon2id:<time>:<memoryKiB>:<threads>:<b64salt>:<hexkey>
//
-// Legacy accounts may still carry the old single-pass salted SHA-256 hash
-// ("sha256:<b64salt>:<hexhash>"); CheckPassword verifies both, and the
-// login paths rehash to Argon2id on successful verification (see
-// NeedsRehash).
+// Only Argon2id is accepted: the prototype has no password-hash migration and
+// accounts are recreated rather than upgraded.
const (
argonTime = 1
argonMemory = 64 * 1024 // KiB
@@ -78,57 +75,33 @@ func HashPassword(password string) (string, error) {
base64.RawStdEncoding.EncodeToString(salt), hex.EncodeToString(key)), nil
}
-// CheckPassword verifies a password against a stored hash in either the
-// current Argon2id format or the legacy salted SHA-256 format.
+// CheckPassword verifies a password against a stored Argon2id hash.
func CheckPassword(password, stored string) bool {
parts := strings.SplitN(stored, ":", 6)
- if len(parts) == 0 {
+ if len(parts) == 0 || parts[0] != "argon2id" {
return false
}
- switch parts[0] {
- case "argon2id":
- if len(parts) != 6 {
- return false
- }
- t, errT := strconv.Atoi(parts[1])
- m, errM := strconv.Atoi(parts[2])
- p, errP := strconv.Atoi(parts[3])
- salt, errSalt := base64.RawStdEncoding.DecodeString(parts[4])
- expected, errKey := hex.DecodeString(parts[5])
- if errT != nil || errM != nil || errP != nil || errSalt != nil || errKey != nil {
- return false
- }
- if t < argonMinTime || t > argonMaxTime ||
- m < argonMinMemory || m > argonMaxMemory ||
- p < argonMinThreads || p > argonMaxThreads ||
- len(expected) < argonMinKeyLen || len(expected) > argonMaxKeyLen {
- // Out-of-range parameters: fail the check instead of trusting the
- // stored values and requesting an enormous allocation.
- return false
- }
- acquireHashSlot()
- key := argon2.IDKey([]byte(password), salt, uint32(t), uint32(m), uint8(p), uint32(len(expected)))
- releaseHashSlot()
- return subtle.ConstantTimeCompare(key, expected) == 1
- case "sha256":
- legacy := strings.SplitN(stored, ":", 3)
- if len(legacy) != 3 {
- return false
- }
- salt, err := base64.RawStdEncoding.DecodeString(legacy[1])
- if err != nil {
- return false
- }
- hash := sha256.Sum256(append(salt, []byte(password)...))
- return subtle.ConstantTimeCompare([]byte(legacy[2]), []byte(fmt.Sprintf("%x", hash))) == 1
- default:
+ if len(parts) != 6 {
return false
}
-}
-
-// NeedsRehash reports whether a stored hash uses the legacy single-pass
-// SHA-256 scheme. Callers rehash with HashPassword after a successful
-// verification and persist the new hash (transparent upgrade on login).
-func NeedsRehash(stored string) bool {
- return strings.HasPrefix(stored, "sha256:")
+ t, errT := strconv.Atoi(parts[1])
+ m, errM := strconv.Atoi(parts[2])
+ p, errP := strconv.Atoi(parts[3])
+ salt, errSalt := base64.RawStdEncoding.DecodeString(parts[4])
+ expected, errKey := hex.DecodeString(parts[5])
+ if errT != nil || errM != nil || errP != nil || errSalt != nil || errKey != nil {
+ return false
+ }
+ if t < argonMinTime || t > argonMaxTime ||
+ m < argonMinMemory || m > argonMaxMemory ||
+ p < argonMinThreads || p > argonMaxThreads ||
+ len(expected) < argonMinKeyLen || len(expected) > argonMaxKeyLen {
+ // Out-of-range parameters: fail the check instead of trusting the
+ // stored values and requesting an enormous allocation.
+ return false
+ }
+ acquireHashSlot()
+ key := argon2.IDKey([]byte(password), salt, uint32(t), uint32(m), uint8(p), uint32(len(expected)))
+ releaseHashSlot()
+ return subtle.ConstantTimeCompare(key, expected) == 1
}