test: OTP 算法 + 加密 + Config + QR 导出 单元测试
- authenticator: HOTP RFC 4226 向量、Base32 往返、SecretData 往返 - crypto: WAGO1 加密解密往返、错误密码、空密码、无效载荷 - config: YAML 明文/加密读写、密码错误、.bak 轮换 - qr: EntryToOtpAuth 各 vendor、URI 往返、默认值省略
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
package qr
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.wxccs.org/iceking2nd/winauth-go/internal/config"
|
||||
)
|
||||
|
||||
func TestEntryToOtpAuthGoogle(t *testing.T) {
|
||||
e := config.Entry{
|
||||
Name: "MyGoogle",
|
||||
Vendor: "google",
|
||||
SecretRaw: "0102030405\t6\tSHA1\t30",
|
||||
}
|
||||
oa, partial, err := EntryToOtpAuth(e)
|
||||
if err != nil {
|
||||
t.Fatalf("EntryToOtpAuth: %v", err)
|
||||
}
|
||||
if partial {
|
||||
t.Error("Google should not be partial")
|
||||
}
|
||||
if oa.Type != "totp" {
|
||||
t.Errorf("Type = %q, want totp", oa.Type)
|
||||
}
|
||||
if oa.Issuer != "Google" {
|
||||
t.Errorf("Issuer = %q, want Google", oa.Issuer)
|
||||
}
|
||||
if oa.Label != "Google:MyGoogle" {
|
||||
t.Errorf("Label = %q", oa.Label)
|
||||
}
|
||||
if oa.Digits != 6 {
|
||||
t.Errorf("Digits = %d, want 6", oa.Digits)
|
||||
}
|
||||
if oa.Algorithm != "SHA1" {
|
||||
t.Errorf("Algorithm = %q, want SHA1", oa.Algorithm)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEntryToOtpAuthHOTP(t *testing.T) {
|
||||
e := config.Entry{
|
||||
Name: "Counter",
|
||||
Vendor: "hotp",
|
||||
SecretRaw: "AABBCCDD\t6\tSHA1\t30|10",
|
||||
}
|
||||
oa, _, err := EntryToOtpAuth(e)
|
||||
if err != nil {
|
||||
t.Fatalf("EntryToOtpAuth: %v", err)
|
||||
}
|
||||
if oa.Type != "hotp" {
|
||||
t.Errorf("Type = %q, want hotp", oa.Type)
|
||||
}
|
||||
if oa.Counter != 10 {
|
||||
t.Errorf("Counter = %d, want 10", oa.Counter)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEntryToOtpAuthBattleNetPartial(t *testing.T) {
|
||||
e := config.Entry{
|
||||
Name: "BNet",
|
||||
Vendor: "battlenet",
|
||||
SecretRaw: "AABB\t8\tSHA1\t30|53455249414C",
|
||||
}
|
||||
oa, partial, err := EntryToOtpAuth(e)
|
||||
if err != nil {
|
||||
t.Fatalf("EntryToOtpAuth: %v", err)
|
||||
}
|
||||
if !partial {
|
||||
t.Error("Battle.Net should be partial")
|
||||
}
|
||||
if oa.Digits != 8 {
|
||||
t.Errorf("Digits = %d, want 8", oa.Digits)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEntryToOtpAuthSteamPartial(t *testing.T) {
|
||||
e := config.Entry{
|
||||
Name: "Steam",
|
||||
Vendor: "steam",
|
||||
SecretRaw: "CCDD\t5\tSHA1\t30|73657269616C|646576696365",
|
||||
}
|
||||
_, partial, err := EntryToOtpAuth(e)
|
||||
if err != nil {
|
||||
t.Fatalf("EntryToOtpAuth: %v", err)
|
||||
}
|
||||
if !partial {
|
||||
t.Error("Steam should be partial")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEntryToOtpAuthEmptySecret(t *testing.T) {
|
||||
e := config.Entry{Name: "Empty", Vendor: "google", SecretRaw: ""}
|
||||
if _, _, err := EntryToOtpAuth(e); err == nil {
|
||||
t.Error("expected error for empty secret")
|
||||
}
|
||||
}
|
||||
|
||||
func TestURIRoundTrip(t *testing.T) {
|
||||
e := config.Entry{
|
||||
Name: "Test",
|
||||
Vendor: "google",
|
||||
SecretRaw: "0102030405\t6\tSHA1\t30",
|
||||
}
|
||||
oa, _, err := EntryToOtpAuth(e)
|
||||
if err != nil {
|
||||
t.Fatalf("EntryToOtpAuth: %v", err)
|
||||
}
|
||||
uri := oa.URI()
|
||||
|
||||
// Parse it back
|
||||
parsed, err := ParseOtpAuth(uri)
|
||||
if err != nil {
|
||||
t.Fatalf("ParseOtpAuth(%q): %v", uri, err)
|
||||
}
|
||||
if parsed.Type != "totp" {
|
||||
t.Errorf("Type = %q, want totp", parsed.Type)
|
||||
}
|
||||
if parsed.SecretBase32 != oa.SecretBase32 {
|
||||
t.Errorf("Secret mismatch: %q vs %q", parsed.SecretBase32, oa.SecretBase32)
|
||||
}
|
||||
}
|
||||
|
||||
func TestURIHOTP(t *testing.T) {
|
||||
oa := &OtpAuth{
|
||||
Type: "hotp",
|
||||
Label: "MyHOTP",
|
||||
SecretBase32: "JBSWY3DPEHPK3PXP",
|
||||
Issuer: "Test",
|
||||
Digits: 6,
|
||||
Counter: 42,
|
||||
}
|
||||
uri := oa.URI()
|
||||
if !strings.Contains(uri, "counter=42") {
|
||||
t.Errorf("URI missing counter: %s", uri)
|
||||
}
|
||||
if !strings.HasPrefix(uri, "otpauth://hotp/") {
|
||||
t.Errorf("URI wrong prefix: %s", uri)
|
||||
}
|
||||
}
|
||||
|
||||
func TestURIDefaultsOmitted(t *testing.T) {
|
||||
oa := &OtpAuth{
|
||||
Type: "totp",
|
||||
SecretBase32: "AAAA",
|
||||
Algorithm: "SHA1",
|
||||
Digits: 6,
|
||||
Period: 30,
|
||||
}
|
||||
uri := oa.URI()
|
||||
if strings.Contains(uri, "algorithm") {
|
||||
t.Errorf("SHA1 should be omitted: %s", uri)
|
||||
}
|
||||
if strings.Contains(uri, "digits") {
|
||||
t.Errorf("digits=6 should be omitted: %s", uri)
|
||||
}
|
||||
if strings.Contains(uri, "period") {
|
||||
t.Errorf("period=30 should be omitted: %s", uri)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user