cb4d88ebdd
- authenticator: HOTP RFC 4226 向量、Base32 往返、SecretData 往返 - crypto: WAGO1 加密解密往返、错误密码、空密码、无效载荷 - config: YAML 明文/加密读写、密码错误、.bak 轮换 - qr: EntryToOtpAuth 各 vendor、URI 往返、默认值省略
113 lines
2.8 KiB
Go
113 lines
2.8 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestSaveLoadPlaintext(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "test.yaml")
|
|
|
|
cfg := &Config{
|
|
Version: 1,
|
|
Language: "en",
|
|
Theme: "dark",
|
|
Entries: []Entry{
|
|
{Name: "Google", Vendor: "google", SecretRaw: "AABB\t6\tSHA1\t30"},
|
|
{Name: "HOTP", Vendor: "hotp", SecretRaw: "CCDD\t6\tSHA1\t30|5"},
|
|
},
|
|
}
|
|
if err := SaveYAML(cfg, path, nil); err != nil {
|
|
t.Fatalf("SaveYAML: %v", err)
|
|
}
|
|
|
|
loaded, err := LoadYAML(path, nil)
|
|
if err != nil {
|
|
t.Fatalf("LoadYAML: %v", err)
|
|
}
|
|
if loaded.Version != 1 {
|
|
t.Errorf("Version = %d, want 1", loaded.Version)
|
|
}
|
|
if len(loaded.Entries) != 2 {
|
|
t.Fatalf("entries = %d, want 2", len(loaded.Entries))
|
|
}
|
|
if loaded.Entries[0].Name != "Google" {
|
|
t.Errorf("Entry[0].Name = %q, want %q", loaded.Entries[0].Name, "Google")
|
|
}
|
|
if loaded.Entries[1].Vendor != "hotp" {
|
|
t.Errorf("Entry[1].Vendor = %q, want %q", loaded.Entries[1].Vendor, "hotp")
|
|
}
|
|
}
|
|
|
|
func TestSaveLoadEncrypted(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "test.yaml")
|
|
pw := []byte("s3cr3t")
|
|
|
|
cfg := &Config{
|
|
Version: 1,
|
|
Encrypted: true,
|
|
Entries: []Entry{
|
|
{Name: "Steam", Vendor: "steam", SecretRaw: "EEFF\t5\tSHA1\t30|SERIAL|DEVICE"},
|
|
},
|
|
}
|
|
if err := SaveYAML(cfg, path, pw); err != nil {
|
|
t.Fatalf("SaveYAML: %v", err)
|
|
}
|
|
|
|
// Load without password → ErrPasswordRequired
|
|
if _, err := LoadYAML(path, nil); err != ErrPasswordRequired {
|
|
t.Errorf("expected ErrPasswordRequired, got %v", err)
|
|
}
|
|
|
|
// Load with wrong password → ErrPasswordWrong
|
|
if _, err := LoadYAML(path, []byte("wrong")); err != ErrPasswordWrong {
|
|
t.Errorf("expected ErrPasswordWrong, got %v", err)
|
|
}
|
|
|
|
// Load with correct password
|
|
loaded, err := LoadYAML(path, pw)
|
|
if err != nil {
|
|
t.Fatalf("LoadYAML: %v", err)
|
|
}
|
|
if len(loaded.Entries) != 1 {
|
|
t.Fatalf("entries = %d, want 1", len(loaded.Entries))
|
|
}
|
|
if loaded.Entries[0].Name != "Steam" {
|
|
t.Errorf("Entry[0].Name = %q, want %q", loaded.Entries[0].Name, "Steam")
|
|
}
|
|
}
|
|
|
|
func TestBackupRotation(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "test.yaml")
|
|
|
|
// First save: no .bak exists yet
|
|
cfg1 := &Config{Version: 1, Entries: []Entry{{Name: "A"}}}
|
|
if err := SaveYAML(cfg1, path, nil); err != nil {
|
|
t.Fatalf("SaveYAML #1: %v", err)
|
|
}
|
|
|
|
// Second save: .bak should be created
|
|
cfg2 := &Config{Version: 1, Entries: []Entry{{Name: "B"}}}
|
|
if err := SaveYAML(cfg2, path, nil); err != nil {
|
|
t.Fatalf("SaveYAML #2: %v", err)
|
|
}
|
|
|
|
bak := path + ".bak"
|
|
if _, err := os.Stat(bak); os.IsNotExist(err) {
|
|
t.Error("expected .bak file to exist after second save")
|
|
}
|
|
}
|
|
|
|
func TestLoadNonexistent(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "nonexistent.yaml")
|
|
_, err := LoadYAML(path, nil)
|
|
if err == nil {
|
|
t.Error("expected error for nonexistent file")
|
|
}
|
|
}
|