Skip to content

Commit

Permalink
inwx: Wait before generating new TOTP TANs
Browse files Browse the repository at this point in the history
This is a workaround for go-acme#1608.  INWX forbids to re-use the same TOTP
twice, but the INWX DNS provider tries to reauthenticate from scratch
on each step.

I believe that this is not easily implementable with the existing Lego
DNS provider interface, so to avoid refactoring that interaction,
let's just make the INWX provider wait a bit until a new token is
available.  A new token is available every 30 seconds.

The current workaround is to invoke Lego many more times.  Retrying at
a higher level is worse than retrying here.

Fixes go-acme#1608

Signed-off-by: Günther Noack <[email protected]>
  • Loading branch information
gnoack authored and ldez committed Jan 18, 2024
1 parent c17f659 commit 88f7442
Showing 1 changed file with 21 additions and 2 deletions.
23 changes: 21 additions & 2 deletions providers/dns/inwx/inwx.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ func NewDefaultConfig() *Config {

// DNSProvider implements the challenge.Provider interface.
type DNSProvider struct {
config *Config
client *goinwx.Client
config *Config
client *goinwx.Client
prevTANCounter int64
}

// NewDNSProvider returns a DNSProvider instance configured for Dyn DNS.
Expand Down Expand Up @@ -202,10 +203,28 @@ func (d *DNSProvider) twoFactorAuth(info *goinwx.LoginResponse) error {
return errors.New("two-factor authentication but no shared secret is given")
}

// 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
}

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

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

0 comments on commit 88f7442

Please sign in to comment.