mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-11 23:26:07 +00:00
fix(api-token): hash tokens at rest and show plaintext only once
Store API tokens as SHA-256 hashes instead of plaintext and return the token value only in the create response. List no longer exposes the token, and the UI drops the Show/Copy buttons in favor of a one-time reveal modal at creation. Match hashes the presented bearer token before the constant-time compare, and a migration hashes any pre-existing plaintext rows in place so existing tokens keep authenticating. Docs and translations updated.
This commit is contained in:
@@ -2,6 +2,9 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
@@ -20,3 +23,25 @@ func IsHashed(s string) bool {
|
||||
_, err := bcrypt.Cost([]byte(s))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// HashTokenSHA256 returns the hex-encoded SHA-256 digest of token. API tokens
|
||||
// are high-entropy random strings, so a fast unsalted digest is sufficient to
|
||||
// keep them irrecoverable at rest while allowing constant-time verification.
|
||||
func HashTokenSHA256(token string) string {
|
||||
sum := sha256.Sum256([]byte(token))
|
||||
return hex.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
// IsSHA256Hex reports whether s looks like a hex-encoded SHA-256 digest
|
||||
// (64 lowercase hex characters), used to skip already-hashed token rows.
|
||||
func IsSHA256Hex(s string) bool {
|
||||
if len(s) != 64 {
|
||||
return false
|
||||
}
|
||||
for _, c := range s {
|
||||
if (c < '0' || c > '9') && (c < 'a' || c > 'f') {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user