package auth import ( "crypto/rand" "crypto/sha256" "encoding/hex" "regexp" ) // Token prefix 常數(security.md §1.3)。 const ( // PairingTokenPrefix 是 pairing token 的固定前綴。 PairingTokenPrefix = "vAc_" // SessionTokenPrefix 是 session token 的固定前綴。 SessionTokenPrefix = "vAs_" // PairingTokenHexLen 是 pairing token 底 hex 字串的字元數(32 chars = 16 bytes)。 PairingTokenHexLen = 32 // SessionTokenHexLen 是 session token 底 hex 字串的字元數(64 chars = 32 bytes)。 SessionTokenHexLen = 64 ) // pairingTokenRegex 驗證 vAc_ + 32 小寫 hex 的完整格式。 var pairingTokenRegex = regexp.MustCompile(`^vAc_[0-9a-f]{32}$`) // sessionTokenRegex 驗證 vAs_ + 64 小寫 hex 的完整格式。 var sessionTokenRegex = regexp.MustCompile(`^vAs_[0-9a-f]{64}$`) // GeneratePairingToken 產生一個符合 `vAc_[0-9a-f]{32}` 格式的 pairing token。 // // 來源:crypto/rand.Read 16 bytes → hex 編碼。 // 失敗時回傳 err(通常僅在系統熵耗盡時發生)。 func GeneratePairingToken() (string, error) { b := make([]byte, PairingTokenHexLen/2) // 16 bytes = 32 hex chars if _, err := rand.Read(b); err != nil { return "", err } return PairingTokenPrefix + hex.EncodeToString(b), nil } // GenerateSessionToken 產生一個符合 `vAs_[0-9a-f]{64}` 格式的 session token。 // // 來源:crypto/rand.Read 32 bytes → hex 編碼。 func GenerateSessionToken() (string, error) { b := make([]byte, SessionTokenHexLen/2) // 32 bytes = 64 hex chars if _, err := rand.Read(b); err != nil { return "", err } return SessionTokenPrefix + hex.EncodeToString(b), nil } // IsValidPairingToken 驗證 token 字串是否符合 pairing token 格式。 func IsValidPairingToken(token string) bool { return pairingTokenRegex.MatchString(token) } // IsValidSessionToken 驗證 token 字串是否符合 session token 格式。 func IsValidSessionToken(token string) bool { return sessionTokenRegex.MatchString(token) } // HashToken 計算 token 的 sha256 hex 字串,供 DB 儲存用(永遠不存明文)。 func HashToken(token string) string { h := sha256.Sum256([]byte(token)) return hex.EncodeToString(h[:]) }