@@ -10,15 +10,17 @@ import (
1010 "github.com/go-acme/lego/v3/log"
1111 "github.com/go-acme/lego/v3/platform/config/env"
1212 "github.com/nrdcg/goinwx"
13+ "github.com/pquerna/otp/totp"
1314)
1415
1516// Environment variables names.
1617const (
1718 envNamespace = "INWX_"
1819
19- EnvUsername = envNamespace + "USERNAME"
20- EnvPassword = envNamespace + "PASSWORD"
21- EnvSandbox = envNamespace + "SANDBOX"
20+ EnvUsername = envNamespace + "USERNAME"
21+ EnvPassword = envNamespace + "PASSWORD"
22+ EnvSharedSecret = envNamespace + "SHARED_SECRET"
23+ EnvSandbox = envNamespace + "SANDBOX"
2224
2325 EnvTTL = envNamespace + "TTL"
2426 EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
@@ -29,6 +31,7 @@ const (
2931type Config struct {
3032 Username string
3133 Password string
34+ SharedSecret string
3235 Sandbox bool
3336 PropagationTimeout time.Duration
3437 PollingInterval time.Duration
@@ -53,7 +56,7 @@ type DNSProvider struct {
5356
5457// NewDNSProvider returns a DNSProvider instance configured for Dyn DNS.
5558// Credentials must be passed in the environment variables:
56- // INWX_USERNAME and INWX_PASSWORD .
59+ // INWX_USERNAME, INWX_PASSWORD, and INWX_SHARED_SECRET .
5760func NewDNSProvider () (* DNSProvider , error ) {
5861 values , err := env .Get (EnvUsername , EnvPassword )
5962 if err != nil {
@@ -63,6 +66,7 @@ func NewDNSProvider() (*DNSProvider, error) {
6366 config := NewDefaultConfig ()
6467 config .Username = values [EnvUsername ]
6568 config .Password = values [EnvPassword ]
69+ config .SharedSecret = env .GetOrFile (EnvSharedSecret )
6670
6771 return NewDNSProviderConfig (config )
6872}
@@ -95,7 +99,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
9599 return fmt .Errorf ("inwx: %w" , err )
96100 }
97101
98- err = d .client .Account .Login ()
102+ info , err : = d .client .Account .Login ()
99103 if err != nil {
100104 return fmt .Errorf ("inwx: %w" , err )
101105 }
@@ -107,6 +111,11 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
107111 }
108112 }()
109113
114+ err = d .twoFactorAuth (info )
115+ if err != nil {
116+ return fmt .Errorf ("inwx: %w" , err )
117+ }
118+
110119 var request = & goinwx.NameserverRecordRequest {
111120 Domain : dns01 .UnFqdn (authZone ),
112121 Name : dns01 .UnFqdn (fqdn ),
@@ -140,7 +149,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
140149 return fmt .Errorf ("inwx: %w" , err )
141150 }
142151
143- err = d .client .Account .Login ()
152+ info , err : = d .client .Account .Login ()
144153 if err != nil {
145154 return fmt .Errorf ("inwx: %w" , err )
146155 }
@@ -152,6 +161,11 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
152161 }
153162 }()
154163
164+ err = d .twoFactorAuth (info )
165+ if err != nil {
166+ return fmt .Errorf ("inwx: %w" , err )
167+ }
168+
155169 response , err := d .client .Nameservers .Info (& goinwx.NameserverInfoRequest {
156170 Domain : dns01 .UnFqdn (authZone ),
157171 Name : dns01 .UnFqdn (fqdn ),
@@ -177,3 +191,20 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
177191func (d * DNSProvider ) Timeout () (timeout , interval time.Duration ) {
178192 return d .config .PropagationTimeout , d .config .PollingInterval
179193}
194+
195+ func (d * DNSProvider ) twoFactorAuth (info * goinwx.LoginResponse ) error {
196+ if info .TFA != "GOOGLE-AUTH" {
197+ return nil
198+ }
199+
200+ if d .config .SharedSecret == "" {
201+ return errors .New ("two factor authentication but no shared secret is given" )
202+ }
203+
204+ tan , err := totp .GenerateCode (d .config .SharedSecret , time .Now ())
205+ if err != nil {
206+ return err
207+ }
208+
209+ return d .client .Account .Unlock (tan )
210+ }
0 commit comments