Skip to content

Commit

Permalink
review: simplification of the algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
ldez committed Jan 18, 2024
1 parent eb9f976 commit 7886a5b
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 16 deletions.
40 changes: 24 additions & 16 deletions providers/dns/inwx/inwx.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type DNSProvider struct {
config *Config
client *goinwx.Client
prevTANCounter int64

Check failure on line 56 in providers/dns/inwx/inwx.go

View workflow job for this annotation

GitHub Actions / Main Process

field `prevTANCounter` is unused (unused)
previousCall time.Time
}

// NewDNSProvider returns a DNSProvider instance configured for Dyn DNS.
Expand Down Expand Up @@ -204,27 +205,34 @@ func (d *DNSProvider) twoFactorAuth(info *goinwx.LoginResponse) error {
}

// INWX forbids re-authentication with a previously used TAN.
// To avoid using the same TAN twice, we wait until the next
// TOTP period and retry.
const s = 30 // seconds per TOTP period
now := time.Now()
tanCounter := now.Unix() / s
if tanCounter == d.prevTANCounter {
nextPeriod := time.Unix(s*(now.Unix()/s)+s, 0)
d := nextPeriod.Sub(now)

log.Infof("inwx: waiting %v for next TOTP token", d)
time.Sleep(d)

now = time.Now()
tanCounter = now.Unix() / s
// To avoid using the same TAN twice, we wait until the next TOTP period and retry.
sleep := d.computeSleep(time.Now())
if sleep != 0 {
log.Infof("inwx: waiting %s for next TOTP token", sleep)
time.Sleep(sleep)
}

tan, err := totp.GenerateCode(d.config.SharedSecret, time.Now())
now := time.Now()

tan, err := totp.GenerateCode(d.config.SharedSecret, now)
if err != nil {
return err
}
d.prevTANCounter = tanCounter

d.previousCall = now

return d.client.Account.Unlock(tan)
}

func (d *DNSProvider) computeSleep(now time.Time) time.Duration {
if d.previousCall.IsZero() {
return 0 * time.Second
}

endPeriod := d.previousCall.Add(30 * time.Second)
if endPeriod.After(now) {
return endPeriod.Sub(now)
}

return 0 * time.Second
}
44 changes: 44 additions & 0 deletions providers/dns/inwx/inwx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package inwx

import (
"testing"
"time"

"github.com/go-acme/lego/v4/platform/tester"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -141,3 +143,45 @@ func TestLivePresentAndCleanup(t *testing.T) {
err = provider.CleanUp(envTest.GetDomain(), "", "123d==")
require.NoError(t, err)
}

func Test_computeSleep(t *testing.T) {
testCases := []struct {
desc string
time string
expected time.Duration
}{
{
desc: "after 30s",
time: "2024-01-01T06:29:20Z",
expected: 0 * time.Second,
},
{
desc: "0s",
time: "2024-01-01T06:29:30Z",
expected: 0 * time.Second,
},
{
desc: "before 30s",
time: "2024-01-01T06:29:50Z", // 10 s
expected: 20 * time.Second,
},
}

now, err := time.Parse(time.RFC3339, "2024-01-01T06:30:00Z")
require.NoError(t, err)

for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()

previous, err := time.Parse(time.RFC3339, test.time)
require.NoError(t, err)

d := &DNSProvider{previousCall: previous}

sleep := d.computeSleep(now)
assert.Equal(t, test.expected, sleep)
})
}
}

0 comments on commit 7886a5b

Please sign in to comment.