Watch
1
0
Fork
You've already forked RedFlag
0
RedFlag/server/internal/security/totp_test.go
Fimeg a4d585c79c code review: 12-finding fan-out — fixes across server, agent, web
HIGH:
- URL sync race: page useEffect now preserves filter params from useFilterUrl
- useFilterUrl: document two-effect pattern (state→URL and URL→state)
- Fleet-join: store nil (not &"") for absent MachineID/PublicKeyFingerprint
- agents.go: same NULL fix for standard registration path

MEDIUM:
- Test assertions: replace CSS class checks with user-visible element assertions
- Updates vuln toggle: fixed-set like other quick filters (was toggling)
- ConfigureSecrets route: restore to welcome-mode server
- Config upgrade: recursive mergeMissingKeys for nested sub-fields + test

LOW:
- LiveOperations: wire FilterBar pills/clearAll/activeCount
- HashTOTPSeed: remove dead code replaced by encrypted storage (migration 058)
- auditor.go: replace unsafe reflect with Recorder wrapper (AUDIT-002)

History filter panel kept as-is (collapsible pattern intentional).
Agents.tsx duplicate buildFilterPills was a false positive (already resolved).
2026-06-11 17:38:08 -04:00

78 lines
2.1 KiB
Go

package security
import (
"encoding/base32"
"testing"
"time"
)
func TestGenerateTOTPSeed(t *testing.T) {
seed, err := GenerateTOTPSeed()
if err != nil {
t.Fatalf("GenerateTOTPSeed failed: %v", err)
}
if len(seed) == 0 {
t.Fatal("seed is empty")
}
// Two seeds should differ.
seed2, err := GenerateTOTPSeed()
if err != nil {
t.Fatalf("GenerateTOTPSeed (2) failed: %v", err)
}
if seed == seed2 {
t.Fatal("two generated seeds are identical")
}
}
func TestTOTPValidation(t *testing.T) {
seed := "JBSWY3DPEHPK3PXP"
// Generate a valid code for a fixed time and verify it passes.
fixed := time.Date(2026, 6, 11, 12, 0, 0, 0, time.UTC)
code := CodeAt(seed, fixed)
if len(code) != 6 {
t.Fatalf("expected 6-digit code, got %q", code)
}
if !ValidateTOTPCodeAt(seed, code, fixed) {
t.Fatalf("code %q rejected at exact time", code)
}
// ±30 seconds should also pass.
if !ValidateTOTPCodeAt(seed, code, fixed.Add(29*time.Second)) {
t.Fatal("code rejected at +29s")
}
if !ValidateTOTPCodeAt(seed, code, fixed.Add(-29*time.Second)) {
t.Fatal("code rejected at -29s")
}
// ±61 seconds should fail (outside ±1 step window).
if ValidateTOTPCodeAt(seed, code, fixed.Add(61*time.Second)) {
t.Fatal("code accepted at +61s — should be outside tolerance")
}
if ValidateTOTPCodeAt(seed, code, fixed.Add(-61*time.Second)) {
t.Fatal("code accepted at -61s — should be outside tolerance")
}
}
func TestTOTPInvalidCode(t *testing.T) {
seed := "JBSWY3DPEHPK3PXP"
fixed := time.Date(2026, 6, 11, 12, 0, 0, 0, time.UTC)
if ValidateTOTPCodeAt(seed, "000000", fixed) {
t.Fatal("all-zero code accepted")
}
if ValidateTOTPCodeAt(seed, "12345", fixed) {
t.Fatal("5-digit code accepted")
}
if ValidateTOTPCodeAt(seed, "1234567", fixed) {
t.Fatal("7-digit code accepted")
}
}
// CodeAt generates the TOTP code at a specific time (exposed for testing).
func CodeAt(seed string, t time.Time) string {
seedBytes, _ := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(seed)
counter := uint64(t.Unix()) / TotpPeriod
return totpAt(seedBytes, counter)
}