1
0
mirror of https://github.com/H0llyW00dzZ/fiber2fa.git synced 2025-02-06 11:02:32 +00:00

Fix Default Time & Update Documentation (#161)

* Fix Default Time

- [+] refactor(tests): update tests to use default TimeSource and Hash from config
- [+] fix(config): change default TimeSource to use UTC time
- [+] fix(otpverifier): update TOTPTime to return UTC time
- [+] test(otpverifier): add test for AdjustSyncWindow function
- [+] refactor(middleware): remove unused options from TOTP verifier config

* Docs [pkg.go.dev] Update Documentation

- [+] docs(otpverifier): clarify TOTPTime function documentation
- [+] The TOTPTime function documentation is updated to provide a clearer explanation of the time zone used and the format of the returned time. It now specifies that the South Pole time zone is used and links to the relevant Wikipedia article for more information. The note is also updated to clarify that the returned time is always expressed in UTC to avoid ambiguity.
This commit is contained in:
H0llyW00dzZ 2024-06-07 07:27:14 +07:00 committed by GitHub
parent e45627e844
commit 5acecf711a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 47 additions and 24 deletions

View File

@ -2,8 +2,6 @@
//
// License: BSD 3-Clause License
// Note: The tests here are outdated and won't work. It will crash because the focus is still on improving the internal implementation.
package twofa_test
import (
@ -243,6 +241,8 @@ func TestMiddleware_Handle(t *testing.T) {
middleware := twofa.New(twofa.Config{
Secret: secret,
Storage: store,
TimeSource: twofa.DefaultConfig.TimeSource,
Hash: twofa.DefaultConfig.Hash,
ContextKey: "user123",
RedirectURL: "/2fa",
CookieMaxAge: 86400,
@ -268,7 +268,9 @@ func TestMiddleware_Handle(t *testing.T) {
// Generate a valid 2FA token
totp := otp.NewTOTPVerifier(otp.Config{
Secret: info.Secret,
Secret: info.Secret,
TimeSource: twofa.DefaultConfig.TimeSource,
Hash: twofa.DefaultConfig.Hash,
})
validToken := totp.GenerateToken()
@ -277,7 +279,9 @@ func TestMiddleware_Handle(t *testing.T) {
// Create a separate instance of the Middleware struct for testing
testMiddleware := &twofa.Middleware{
Config: &twofa.Config{
Secret: secret,
Secret: secret,
TimeSource: twofa.DefaultConfig.TimeSource,
Hash: twofa.DefaultConfig.Hash,
},
}
@ -1253,6 +1257,8 @@ func TestMiddlewareUUIDContextKey_Handle(t *testing.T) {
middleware := twofa.New(twofa.Config{
Secret: secret,
Storage: store,
TimeSource: twofa.DefaultConfig.TimeSource,
Hash: twofa.DefaultConfig.Hash,
ContextKey: contextKey,
RedirectURL: "/2fa",
CookieMaxAge: 86400,
@ -1278,7 +1284,9 @@ func TestMiddlewareUUIDContextKey_Handle(t *testing.T) {
// Generate a valid 2FA token
totp := otp.NewTOTPVerifier(otp.Config{
Secret: info.Secret,
Secret: info.Secret,
TimeSource: twofa.DefaultConfig.TimeSource,
Hash: twofa.DefaultConfig.Hash,
})
validToken := totp.GenerateToken()
@ -1287,7 +1295,9 @@ func TestMiddlewareUUIDContextKey_Handle(t *testing.T) {
// Create a separate instance of the Middleware struct for testing
testMiddleware := &twofa.Middleware{
Config: &twofa.Config{
Secret: secret,
Secret: secret,
TimeSource: twofa.DefaultConfig.TimeSource,
Hash: twofa.DefaultConfig.Hash,
},
}

View File

@ -221,7 +221,7 @@ var DefaultConfig = Config{
DigitsCount: otp.DefaultConfig.Digits,
Period: otp.DefaultConfig.Period,
Hash: otp.SHA512,
TimeSource: otp.DefaultConfig.TOTPTime().UTC,
TimeSource: otp.DefaultConfig.TOTPTime,
SyncWindow: otp.DefaultConfig.SyncWindow,
SkipCookies: nil,
CookieName: "twofa_cookie",

View File

@ -440,11 +440,11 @@ func (v *Config) cryptopowpow10(exponent int) uint64 {
return result
}
// TOTPTime returns the current time in the https://en.wikipedia.org/wiki/South_Pole time zone.
// TOTPTime returns the current time in the South Pole (see https://en.wikipedia.org/wiki/Time_in_Antarctica) time zone.
// It is used as the default time source for TOTP if no custom time source is provided (nil) and the sync window is set to -1.
//
// Note: The returned time is always expressed in UTC (Coordinated Universal Time) to avoid any ambiguity caused by local time zone offsets.
func (v *Config) TOTPTime() time.Time {
location, _ := time.LoadLocation("Antarctica/South_Pole")
return time.Now().In(location)
return time.Now().In(location).UTC()
}

View File

@ -1268,14 +1268,14 @@ func TestHOTPVerifier_VerifySyncWindowWithResync(t *testing.T) {
Secret: secret,
Counter: initialCounter,
Hasher: otpverifier.Hashers[hashFunc],
SyncWindow: otpverifier.HighStrict,
ResyncWindowDelay: 50 * time.Millisecond,
SyncWindow: otpverifier.MediumStrict,
ResyncWindowDelay: 1 * time.Second,
}
verifier := otpverifier.NewHOTPVerifier(config)
// Generate a token for the current counter value
verifier.Hotp.At(int(initialCounter))
verifier.Hotp.At(int(initialCounter + 5))
// Verify this token should fail
if verifier.Verify("invalid") {
@ -1283,7 +1283,7 @@ func TestHOTPVerifier_VerifySyncWindowWithResync(t *testing.T) {
}
// Generate a token for a counter value within the sync window
withinWindowToken := verifier.Hotp.At(int(initialCounter) + otpverifier.HighStrict)
withinWindowToken := verifier.Hotp.At(int(initialCounter) + otpverifier.MediumStrict)
// Verify this token should also pass
if !verifier.Verify(withinWindowToken) {
@ -1291,17 +1291,31 @@ func TestHOTPVerifier_VerifySyncWindowWithResync(t *testing.T) {
}
// Verify that the counter has been updated to the last verified counter + 1
if verifier.GetCounter() != initialCounter+uint64(otpverifier.HighStrict)+1 {
if verifier.GetCounter() != initialCounter+uint64(otpverifier.MediumStrict)+1 {
t.Errorf("Counter was not updated correctly after sync window verification (hash function: %s)", hashFunc)
}
// Generate a token for a counter value outside the sync window
outsideWindowToken := verifier.Hotp.At(int(initialCounter) + otpverifier.HighStrict + 3)
outsideWindowToken := verifier.Hotp.At(int(initialCounter) + otpverifier.MediumStrict + 6)
// Verify this token should fail
if verifier.Verify(outsideWindowToken) {
t.Errorf("Token outside sync window verified but should not have (hash function: %s)", hashFunc)
}
// Trigger the AdjustSyncWindow function
verifier.AdjustSyncWindow(config.CounterMismatch)
// Get the actual sync window size
actualSyncWindow := verifier.GetSyncWindow()
// Get the expected sync window range for MediumStrict
expectedRange := otpverifier.SyncWindowRanges[otpverifier.MediumStrict]
// Check if the actual sync window size falls within the expected range
if actualSyncWindow < expectedRange[0] || actualSyncWindow > expectedRange[1] {
t.Errorf("Expected sync window size to be within the range %v, but got %d", expectedRange, actualSyncWindow)
}
}
}

View File

@ -49,7 +49,7 @@ func NewTOTPVerifier(config ...Config) *TOTPVerifier {
// The RFC 6238 (TOTP specification) does not define a specific synchronization window, but it is a common practice to implement it in TOTP systems to accommodate
// for real-world scenarios where perfect clock synchronization is not always possible (e.g, traveling (in airplane), living in antartica, ISS-NASA).
if c.TimeSource == nil && c.SyncWindow != 0 {
c.TimeSource = DefaultConfig.TOTPTime().UTC
c.TimeSource = DefaultConfig.TOTPTime
c.SyncWindow = DefaultConfig.SyncWindow
}

View File

@ -301,16 +301,15 @@ func (m *Middleware) extractToken(c *fiber.Ctx) string {
// verifyToken verifies the provided token against the user's secret and returns the updated Info struct.
func (m *Middleware) verifyToken(token string) bool {
totp := otp.NewTOTPVerifier(otp.Config{
Secret: m.Info.GetSecret(),
Digits: m.Config.DigitsCount,
Period: m.Config.Period,
SyncWindow: m.Config.SyncWindow,
UseSignature: otp.DefaultConfig.UseSignature,
Hash: m.Config.Hash,
TimeSource: m.Config.TimeSource,
Secret: m.Info.GetSecret(),
Digits: m.Config.DigitsCount,
Period: m.Config.Period,
SyncWindow: m.Config.SyncWindow,
Hash: m.Config.Hash,
TimeSource: m.Config.TimeSource,
})
if !totp.Verify(token, "") {
if !totp.Verify(token) {
return false
}