@@ -10,15 +10,17 @@ import (
10
10
"github.com/go-acme/lego/v3/log"
11
11
"github.com/go-acme/lego/v3/platform/config/env"
12
12
"github.com/nrdcg/goinwx"
13
+ "github.com/pquerna/otp/totp"
13
14
)
14
15
15
16
// Environment variables names.
16
17
const (
17
18
envNamespace = "INWX_"
18
19
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"
22
24
23
25
EnvTTL = envNamespace + "TTL"
24
26
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
@@ -29,6 +31,7 @@ const (
29
31
type Config struct {
30
32
Username string
31
33
Password string
34
+ SharedSecret string
32
35
Sandbox bool
33
36
PropagationTimeout time.Duration
34
37
PollingInterval time.Duration
@@ -53,7 +56,7 @@ type DNSProvider struct {
53
56
54
57
// NewDNSProvider returns a DNSProvider instance configured for Dyn DNS.
55
58
// Credentials must be passed in the environment variables:
56
- // INWX_USERNAME and INWX_PASSWORD .
59
+ // INWX_USERNAME, INWX_PASSWORD, and INWX_SHARED_SECRET .
57
60
func NewDNSProvider () (* DNSProvider , error ) {
58
61
values , err := env .Get (EnvUsername , EnvPassword )
59
62
if err != nil {
@@ -63,6 +66,7 @@ func NewDNSProvider() (*DNSProvider, error) {
63
66
config := NewDefaultConfig ()
64
67
config .Username = values [EnvUsername ]
65
68
config .Password = values [EnvPassword ]
69
+ config .SharedSecret = env .GetOrFile (EnvSharedSecret )
66
70
67
71
return NewDNSProviderConfig (config )
68
72
}
@@ -95,7 +99,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
95
99
return fmt .Errorf ("inwx: %w" , err )
96
100
}
97
101
98
- err = d .client .Account .Login ()
102
+ info , err : = d .client .Account .Login ()
99
103
if err != nil {
100
104
return fmt .Errorf ("inwx: %w" , err )
101
105
}
@@ -107,6 +111,11 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
107
111
}
108
112
}()
109
113
114
+ err = d .twoFactorAuth (info )
115
+ if err != nil {
116
+ return fmt .Errorf ("inwx: %w" , err )
117
+ }
118
+
110
119
var request = & goinwx.NameserverRecordRequest {
111
120
Domain : dns01 .UnFqdn (authZone ),
112
121
Name : dns01 .UnFqdn (fqdn ),
@@ -140,7 +149,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
140
149
return fmt .Errorf ("inwx: %w" , err )
141
150
}
142
151
143
- err = d .client .Account .Login ()
152
+ info , err : = d .client .Account .Login ()
144
153
if err != nil {
145
154
return fmt .Errorf ("inwx: %w" , err )
146
155
}
@@ -152,6 +161,11 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
152
161
}
153
162
}()
154
163
164
+ err = d .twoFactorAuth (info )
165
+ if err != nil {
166
+ return fmt .Errorf ("inwx: %w" , err )
167
+ }
168
+
155
169
response , err := d .client .Nameservers .Info (& goinwx.NameserverInfoRequest {
156
170
Domain : dns01 .UnFqdn (authZone ),
157
171
Name : dns01 .UnFqdn (fqdn ),
@@ -177,3 +191,20 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
177
191
func (d * DNSProvider ) Timeout () (timeout , interval time.Duration ) {
178
192
return d .config .PropagationTimeout , d .config .PollingInterval
179
193
}
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