| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- package credential
- import (
- "context"
- "crypto/md5"
- "crypto/sha1"
- "encoding/hex"
- "strings"
- "testing"
- )
- func md5hex(s string) string { sum := md5.Sum([]byte(s)); return hex.EncodeToString(sum[:]) }
- func sha1hex(s string) string { sum := sha1.Sum([]byte(s)); return hex.EncodeToString(sum[:]) }
- // TestHashArgon2RoundTrip 验证 argon2 哈希往返(新注册/改密/惰性升级入口)。
- func TestHashArgon2RoundTrip(t *testing.T) {
- enc, err := HashArgon2("X#9f2k")
- if err != nil {
- t.Fatalf("HashArgon2 失败: %v", err)
- }
- if !strings.HasPrefix(enc, "argon2id$v=19$") {
- t.Errorf("argon2 编码串应前缀 argon2id$v=19$,得 %q", enc)
- }
- if !VerifyArgon2(enc, "X#9f2k") {
- t.Errorf("正确密码应匹配")
- }
- if VerifyArgon2(enc, "wrong") {
- t.Errorf("错误密码应不匹配")
- }
- }
- // TestCheckMD5Salt 验证教务旧算法 md5(password+salt) 路由 + 惰性升级标记。
- func TestCheckMD5Salt(t *testing.T) {
- const pw, salt = "P@ssw0rd", "aBcDeF"
- stored := md5hex(pw + salt)
- res, err := Check(context.Background(), pw, stored, salt, HashVersionMD5Salt)
- if err != nil {
- t.Fatalf("Check 意外错误: %v", err)
- }
- if !res.Match || !res.NeedsUpgrade {
- t.Errorf("md5_salt 命中应 Match=true 且 NeedsUpgrade=true,得 %+v", res)
- }
- // 错误密码
- res2, _ := Check(context.Background(), "nope", stored, salt, HashVersionMD5Salt)
- if res2.Match {
- t.Errorf("md5 错误密码应不匹配")
- }
- }
- // TestCheckShASalt 验证教学旧算法 sha1(password+salt) 路由。
- func TestCheckShASalt(t *testing.T) {
- const pw, salt = "teach123", "sAlT12"
- stored := sha1hex(pw + salt)
- res, err := Check(context.Background(), pw, stored, salt, HashVersionShASalt)
- if err != nil {
- t.Fatalf("Check 意外错误: %v", err)
- }
- if !res.Match || !res.NeedsUpgrade {
- t.Errorf("sha_salt 命中应 Match=true 且 NeedsUpgrade=true,得 %+v", res)
- }
- }
- // TestCheckArgon2 验证目标算法 argon2 路由(命中不触发升级)。
- func TestCheckArgon2(t *testing.T) {
- enc, _ := HashArgon2("argon-pw")
- res, err := Check(context.Background(), "argon-pw", enc, "", HashVersionArgon2)
- if err != nil {
- t.Fatalf("Check 意外错误: %v", err)
- }
- if !res.Match || res.NeedsUpgrade {
- t.Errorf("argon2 命中应 Match=true 且 NeedsUpgrade=false(已是终态),得 %+v", res)
- }
- }
- // TestCheckHexCaseFold 验证旧 hex 大写 storedHash 折叠比较(历史脚本大小写差异,数据保真例外)。
- func TestCheckHexCaseFold(t *testing.T) {
- const pw, salt = "fold123", "zz"
- storedUpper := strings.ToUpper(md5hex(pw + salt))
- res, err := Check(context.Background(), pw, storedUpper, salt, HashVersionMD5Salt)
- if err != nil {
- t.Fatalf("Check 意外错误: %v", err)
- }
- if !res.Match {
- t.Errorf("大写 hex storedHash 应折叠命中,得 Match=%v", res.Match)
- }
- }
- // TestCheckUnknownVersion 验证未知 hash_version 拒绝(非密码错误,走告警分支)。
- func TestCheckUnknownVersion(t *testing.T) {
- res, err := Check(context.Background(), "pw", "abc", "", "weird_version")
- if err == nil {
- t.Fatalf("未知 version 应报错")
- }
- if !strings.Contains(err.Error(), "weird_version") {
- t.Errorf("错误应含实际 version 值,得 %q", err.Error())
- }
- if res.Match {
- t.Errorf("未知 version 不应 Match")
- }
- _ = ErrUnknownVersion
- }
- // TestCheckEmptyHash 验证空密码哈希(账号无凭证,需运维重建)。
- func TestCheckEmptyHash(t *testing.T) {
- _, err := Check(context.Background(), "pw", "", "salt", HashVersionMD5Salt)
- if err == nil {
- t.Fatalf("空 storedHash 应报错")
- }
- if !strings.Contains(err.Error(), "无密码哈希") {
- t.Errorf("错误应提示无密码哈希,得 %q", err.Error())
- }
- }
|