feat: joker username and password. (#927)

This commit is contained in:
Ludovic Fernandez 2019-07-17 02:39:17 +02:00 committed by GitHub
parent 84d9795793
commit 0dbc28193b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 214 additions and 38 deletions

View file

@ -762,6 +762,8 @@ func displayDNSHelp(name string) error {
ew.writeln(`Credentials:`)
ew.writeln(` - "JOKER_API_KEY": API key`)
ew.writeln(` - "JOKER_PASSWORD": Joker.com password`)
ew.writeln(` - "JOKER_USERNAME": Joker.com username (email address)`)
ew.writeln()
ew.writeln(`Additional Configuration:`)

View file

@ -21,6 +21,10 @@ Configuration for [Joker](https://joker.com).
Here is an example bash command using the Joker provider:
```bash
JOKER_USERNAME=<your email> \
JOKER_PASSWORD=<your password> \
lego --dns joker --domains my.domain.com --email my@email.com run
# or
JOKER_API_KEY=<your API key> \
lego --dns joker --domains my.domain.com --email my@email.com run
```
@ -33,6 +37,8 @@ lego --dns joker --domains my.domain.com --email my@email.com run
| Environment Variable Name | Description |
|-----------------------|-------------|
| `JOKER_API_KEY` | API key |
| `JOKER_PASSWORD` | Joker.com password |
| `JOKER_USERNAME` | Joker.com username (email address) |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.
More information [here](/lego/dns/#configuration-and-credentials).

View file

@ -70,7 +70,20 @@ func (d *DNSProvider) login() (*response, error) {
return nil, nil
}
response, err := d.postRequest("login", url.Values{"api-key": {d.config.APIKey}})
var values url.Values
switch {
case d.config.Username != "" && d.config.Password != "":
values = url.Values{
"username": {d.config.Username},
"password": {d.config.Password},
}
case d.config.APIKey != "":
values = url.Values{"api-key": {d.config.APIKey}}
default:
return nil, fmt.Errorf("no username and password or api-key")
}
response, err := d.postRequest("login", values)
if err != nil {
return response, err
}

View file

@ -12,9 +12,15 @@ import (
)
const (
correctAuth = "123"
incorrectAuth = "321"
serverErrorAuth = "500"
correctAPIKey = "123"
incorrectAPIKey = "321"
serverErrorAPIKey = "500"
)
const (
correctUsername = "lego"
incorrectUsername = "not_lego"
serverErrorUsername = "error"
)
func setup() (*http.ServeMux, *httptest.Server) {
@ -23,35 +29,35 @@ func setup() (*http.ServeMux, *httptest.Server) {
return mux, server
}
func TestDNSProvider_login(t *testing.T) {
func TestDNSProvider_login_api_key(t *testing.T) {
testCases := []struct {
desc string
authKey string
apiKey string
expectedError bool
expectedStatusCode int
expectedAuthSid string
}{
{
desc: "correct key",
authKey: correctAuth,
apiKey: correctAPIKey,
expectedStatusCode: 0,
expectedAuthSid: correctAuth,
expectedAuthSid: correctAPIKey,
},
{
desc: "incorrect key",
authKey: incorrectAuth,
apiKey: incorrectAPIKey,
expectedStatusCode: 2200,
expectedError: true,
},
{
desc: "server error",
authKey: serverErrorAuth,
apiKey: serverErrorAPIKey,
expectedStatusCode: -500,
expectedError: true,
},
{
desc: "non-ok status code",
authKey: "333",
apiKey: "333",
expectedStatusCode: 2202,
expectedError: true,
},
@ -64,11 +70,11 @@ func TestDNSProvider_login(t *testing.T) {
require.Equal(t, "POST", r.Method)
switch r.FormValue("api-key") {
case correctAuth:
case correctAPIKey:
_, _ = io.WriteString(w, "Status-Code: 0\nStatus-Text: OK\nAuth-Sid: 123\n\ncom\nnet")
case incorrectAuth:
case incorrectAPIKey:
_, _ = io.WriteString(w, "Status-Code: 2200\nStatus-Text: Authentication error")
case serverErrorAuth:
case serverErrorAPIKey:
http.NotFound(w, r)
default:
_, _ = io.WriteString(w, "Status-Code: 2202\nStatus-Text: OK\n\ncom\nnet")
@ -79,7 +85,89 @@ func TestDNSProvider_login(t *testing.T) {
t.Run(test.desc, func(t *testing.T) {
config := NewDefaultConfig()
config.BaseURL = server.URL
config.APIKey = test.authKey
config.APIKey = test.apiKey
p, err := NewDNSProviderConfig(config)
require.NoError(t, err)
require.NotNil(t, p)
response, err := p.login()
if test.expectedError {
require.Error(t, err)
} else {
require.NoError(t, err)
require.NotNil(t, response)
assert.Equal(t, test.expectedStatusCode, response.StatusCode)
assert.Equal(t, test.expectedAuthSid, response.AuthSid)
}
})
}
}
func TestDNSProvider_login_username(t *testing.T) {
testCases := []struct {
desc string
username string
password string
expectedError bool
expectedStatusCode int
expectedAuthSid string
}{
{
desc: "correct username and password",
username: correctUsername,
password: "go-acme",
expectedError: false,
expectedStatusCode: 0,
expectedAuthSid: correctAPIKey,
},
{
desc: "incorrect username",
username: incorrectUsername,
password: "go-acme",
expectedStatusCode: 2200,
expectedError: true,
},
{
desc: "server error",
username: serverErrorUsername,
password: "go-acme",
expectedStatusCode: -500,
expectedError: true,
},
{
desc: "non-ok status code",
username: "random",
password: "go-acme",
expectedStatusCode: 2202,
expectedError: true,
},
}
mux, server := setup()
defer server.Close()
mux.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "POST", r.Method)
switch r.FormValue("username") {
case correctUsername:
_, _ = io.WriteString(w, "Status-Code: 0\nStatus-Text: OK\nAuth-Sid: 123\n\ncom\nnet")
case incorrectUsername:
_, _ = io.WriteString(w, "Status-Code: 2200\nStatus-Text: Authentication error")
case serverErrorUsername:
http.NotFound(w, r)
default:
_, _ = io.WriteString(w, "Status-Code: 2202\nStatus-Text: OK\n\ncom\nnet")
}
})
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
config := NewDefaultConfig()
config.BaseURL = server.URL
config.Username = test.username
config.Password = test.password
p, err := NewDNSProviderConfig(config)
require.NoError(t, err)
@ -107,12 +195,12 @@ func TestDNSProvider_logout(t *testing.T) {
}{
{
desc: "correct auth-sid",
authSid: correctAuth,
authSid: correctAPIKey,
expectedStatusCode: 0,
},
{
desc: "incorrect auth-sid",
authSid: incorrectAuth,
authSid: incorrectAPIKey,
expectedStatusCode: 2200,
},
{
@ -122,7 +210,7 @@ func TestDNSProvider_logout(t *testing.T) {
},
{
desc: "server error",
authSid: serverErrorAuth,
authSid: serverErrorAPIKey,
expectedError: true,
},
}
@ -134,9 +222,9 @@ func TestDNSProvider_logout(t *testing.T) {
require.Equal(t, "POST", r.Method)
switch r.FormValue("auth-sid") {
case correctAuth:
case correctAPIKey:
_, _ = io.WriteString(w, "Status-Code: 0\nStatus-Text: OK\n")
case incorrectAuth:
case incorrectAPIKey:
_, _ = io.WriteString(w, "Status-Code: 2200\nStatus-Text: Authentication error")
default:
http.NotFound(w, r)
@ -179,20 +267,20 @@ func TestDNSProvider_getZone(t *testing.T) {
}{
{
desc: "correct auth-sid, known domain",
authSid: correctAuth,
authSid: correctAPIKey,
domain: "known",
zone: testZone,
expectedStatusCode: 0,
},
{
desc: "incorrect auth-sid, known domain",
authSid: incorrectAuth,
authSid: incorrectAPIKey,
domain: "known",
expectedStatusCode: 2202,
},
{
desc: "correct auth-sid, unknown domain",
authSid: correctAuth,
authSid: correctAPIKey,
domain: "unknown",
expectedStatusCode: 2202,
},
@ -213,9 +301,9 @@ func TestDNSProvider_getZone(t *testing.T) {
domain := r.FormValue("domain")
switch {
case authSid == correctAuth && domain == "known":
case authSid == correctAPIKey && domain == "known":
_, _ = io.WriteString(w, "Status-Code: 0\nStatus-Text: OK\n\n"+testZone)
case authSid == incorrectAuth || (authSid == correctAuth && domain == "unknown"):
case authSid == incorrectAPIKey || (authSid == correctAPIKey && domain == "unknown"):
_, _ = io.WriteString(w, "Status-Code: 2202\nStatus-Text: Authorization error")
default:
http.NotFound(w, r)

View file

@ -18,6 +18,8 @@ type Config struct {
Debug bool
BaseURL string
APIKey string
Username string
Password string
PropagationTimeout time.Duration
PollingInterval time.Duration
TTL int
@ -50,11 +52,17 @@ type DNSProvider struct {
func NewDNSProvider() (*DNSProvider, error) {
values, err := env.Get("JOKER_API_KEY")
if err != nil {
return nil, fmt.Errorf("joker: %v", err)
var errU error
values, errU = env.Get("JOKER_USERNAME", "JOKER_PASSWORD")
if errU != nil {
return nil, fmt.Errorf("joker: %v or %v", errU, err)
}
}
config := NewDefaultConfig()
config.APIKey = values["JOKER_API_KEY"]
config.Username = values["JOKER_USERNAME"]
config.Password = values["JOKER_PASSWORD"]
return NewDNSProviderConfig(config)
}
@ -66,8 +74,10 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
}
if config.APIKey == "" {
if config.Username == "" || config.Password == "" {
return nil, fmt.Errorf("joker: credentials missing")
}
}
if !strings.HasSuffix(config.BaseURL, "/") {
config.BaseURL += "/"

View file

@ -5,6 +5,10 @@ Code = "joker"
Since = "v2.6.0"
Example = '''
JOKER_USERNAME=<your email> \
JOKER_PASSWORD=<your password> \
lego --dns joker --domains my.domain.com --email my@email.com run
# or
JOKER_API_KEY=<your API key> \
lego --dns joker --domains my.domain.com --email my@email.com run
'''
@ -12,6 +16,8 @@ lego --dns joker --domains my.domain.com --email my@email.com run
[Configuration]
[Configuration.Credentials]
JOKER_API_KEY = "API key"
JOKER_USERNAME = "Joker.com username (email address)"
JOKER_PASSWORD = "Joker.com password"
[Configuration.Additional]
JOKER_POLLING_INTERVAL = "Time between DNS propagation check"
JOKER_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"

View file

@ -9,7 +9,8 @@ import (
"github.com/stretchr/testify/require"
)
var envTest = tester.NewEnvTest("JOKER_API_KEY").WithDomain("JOKER_DOMAIN")
var envTest = tester.NewEnvTest("JOKER_API_KEY", "JOKER_USERNAME", "JOKER_PASSWORD").
WithDomain("JOKER_DOMAIN")
func TestNewDNSProvider(t *testing.T) {
testCases := []struct {
@ -18,17 +19,44 @@ func TestNewDNSProvider(t *testing.T) {
expected string
}{
{
desc: "success",
desc: "success API key",
envVars: map[string]string{
"JOKER_API_KEY": "123",
},
},
{
desc: "missing key",
desc: "success username password",
envVars: map[string]string{
"JOKER_USERNAME": "123",
"JOKER_PASSWORD": "123",
},
},
{
desc: "missing credentials",
envVars: map[string]string{
"JOKER_API_KEY": "",
"JOKER_USERNAME": "",
"JOKER_PASSWORD": "",
},
expected: "joker: some credentials information are missing: JOKER_API_KEY",
expected: "joker: some credentials information are missing: JOKER_USERNAME,JOKER_PASSWORD or some credentials information are missing: JOKER_API_KEY",
},
{
desc: "missing password",
envVars: map[string]string{
"JOKER_API_KEY": "",
"JOKER_USERNAME": "123",
"JOKER_PASSWORD": "",
},
expected: "joker: some credentials information are missing: JOKER_PASSWORD or some credentials information are missing: JOKER_API_KEY",
},
{
desc: "missing username",
envVars: map[string]string{
"JOKER_API_KEY": "",
"JOKER_USERNAME": "",
"JOKER_PASSWORD": "123",
},
expected: "joker: some credentials information are missing: JOKER_USERNAME or some credentials information are missing: JOKER_API_KEY",
},
}
@ -55,14 +83,22 @@ func TestNewDNSProvider(t *testing.T) {
func TestNewDNSProviderConfig(t *testing.T) {
testCases := []struct {
desc string
authKey string
apiKey string
username string
password string
baseURL string
expected string
expectedBaseURL string
}{
{
desc: "success",
authKey: "123",
desc: "success api key",
apiKey: "123",
expectedBaseURL: defaultBaseURL,
},
{
desc: "success username and password",
username: "123",
password: "123",
expectedBaseURL: defaultBaseURL,
},
{
@ -70,15 +106,27 @@ func TestNewDNSProviderConfig(t *testing.T) {
expected: "joker: credentials missing",
expectedBaseURL: defaultBaseURL,
},
{
desc: "missing credentials: username",
expected: "joker: credentials missing",
username: "123",
expectedBaseURL: defaultBaseURL,
},
{
desc: "missing credentials: password",
expected: "joker: credentials missing",
password: "123",
expectedBaseURL: defaultBaseURL,
},
{
desc: "Base URL should ends with /",
authKey: "123",
apiKey: "123",
baseURL: "http://example.com",
expectedBaseURL: "http://example.com/",
},
{
desc: "Base URL already ends with /",
authKey: "123",
apiKey: "123",
baseURL: "http://example.com/",
expectedBaseURL: "http://example.com/",
},
@ -87,7 +135,10 @@ func TestNewDNSProviderConfig(t *testing.T) {
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
config := NewDefaultConfig()
config.APIKey = test.authKey
config.APIKey = test.apiKey
config.Username = test.username
config.Password = test.password
if test.baseURL != "" {
config.BaseURL = test.baseURL
}