2021-12-25 02:16:58 +01:00
|
|
|
package server
|
2021-12-10 22:35:47 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
2021-12-25 02:16:58 +01:00
|
|
|
"orblivion/lbry-id/auth"
|
|
|
|
"orblivion/lbry-id/wallet"
|
2021-12-10 22:35:47 +01:00
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
2021-12-19 23:24:43 +01:00
|
|
|
func TestServerAuthHandlerSuccess(t *testing.T) {
|
2021-12-25 02:16:58 +01:00
|
|
|
testAuth := TestAuth{TestToken: auth.AuthTokenString("seekrit")}
|
2021-12-10 22:35:47 +01:00
|
|
|
testStore := TestStore{}
|
2021-12-25 02:16:58 +01:00
|
|
|
s := Server{&testAuth, &testStore, &wallet.WalletUtil{}}
|
2021-12-10 22:35:47 +01:00
|
|
|
|
2022-06-07 19:25:14 +02:00
|
|
|
requestBody := []byte(`{"deviceId": "dev-1", "email": "abc@example.com", "password": "123"}`)
|
2021-12-10 22:35:47 +01:00
|
|
|
|
2022-06-08 00:24:01 +02:00
|
|
|
req := httptest.NewRequest(http.MethodPost, PathAuthToken, bytes.NewBuffer(requestBody))
|
2021-12-10 22:35:47 +01:00
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
2022-06-08 00:24:01 +02:00
|
|
|
s.getAuthToken(w, req)
|
2021-12-10 22:35:47 +01:00
|
|
|
body, _ := ioutil.ReadAll(w.Body)
|
|
|
|
|
2021-12-25 02:16:58 +01:00
|
|
|
var result auth.AuthToken
|
2021-12-10 22:35:47 +01:00
|
|
|
|
|
|
|
if want, got := http.StatusOK, w.Result().StatusCode; want != got {
|
|
|
|
t.Errorf("StatusCode: expected %s (%d), got %s (%d)", http.StatusText(want), want, http.StatusText(got), got)
|
|
|
|
}
|
|
|
|
|
|
|
|
err := json.Unmarshal(body, &result)
|
|
|
|
|
|
|
|
if err != nil || result.Token != testAuth.TestToken {
|
|
|
|
t.Errorf("Expected auth response to contain token: result: %+v err: %+v", string(body), err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !testStore.SaveTokenCalled {
|
|
|
|
t.Errorf("Expected Store.SaveToken to be called")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-19 23:24:43 +01:00
|
|
|
func TestServerAuthHandlerErrors(t *testing.T) {
|
2021-12-10 22:35:47 +01:00
|
|
|
tt := []struct {
|
|
|
|
name string
|
|
|
|
method string
|
|
|
|
requestBody string
|
|
|
|
expectedStatusCode int
|
|
|
|
expectedErrorString string
|
|
|
|
|
2022-06-07 19:25:14 +02:00
|
|
|
authFailLogin bool
|
2021-12-10 22:35:47 +01:00
|
|
|
authFailGenToken bool
|
|
|
|
storeFailSave bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "bad method",
|
|
|
|
method: http.MethodGet,
|
|
|
|
requestBody: "",
|
|
|
|
expectedStatusCode: http.StatusMethodNotAllowed,
|
|
|
|
expectedErrorString: http.StatusText(http.StatusMethodNotAllowed),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "request body too large",
|
|
|
|
method: http.MethodPost,
|
2022-06-07 19:25:14 +02:00
|
|
|
requestBody: fmt.Sprintf(`{"password": "%s"}`, strings.Repeat("a", 10000)),
|
2021-12-10 22:35:47 +01:00
|
|
|
expectedStatusCode: http.StatusRequestEntityTooLarge,
|
|
|
|
expectedErrorString: http.StatusText(http.StatusRequestEntityTooLarge),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "malformed request body JSON",
|
|
|
|
method: http.MethodPost,
|
|
|
|
requestBody: "{",
|
|
|
|
expectedStatusCode: http.StatusBadRequest,
|
|
|
|
expectedErrorString: http.StatusText(http.StatusBadRequest) + ": Malformed request body JSON",
|
|
|
|
},
|
2021-12-25 02:16:58 +01:00
|
|
|
{
|
|
|
|
name: "body JSON failed validation",
|
|
|
|
method: http.MethodPost,
|
|
|
|
requestBody: "{}",
|
|
|
|
expectedStatusCode: http.StatusBadRequest,
|
|
|
|
expectedErrorString: http.StatusText(http.StatusBadRequest) + ": Request failed validation",
|
|
|
|
},
|
2021-12-10 22:35:47 +01:00
|
|
|
{
|
2022-06-07 19:25:14 +02:00
|
|
|
name: "login fail",
|
2021-12-10 22:35:47 +01:00
|
|
|
method: http.MethodPost,
|
2022-06-07 19:25:14 +02:00
|
|
|
// so long as the JSON is well-formed, the content doesn't matter here since the password check will be stubbed out
|
|
|
|
requestBody: `{"deviceId": "dev-1", "email": "abc@example.com", "password": "123"}`,
|
|
|
|
expectedStatusCode: http.StatusUnauthorized,
|
|
|
|
expectedErrorString: http.StatusText(http.StatusUnauthorized) + ": No match for email and password",
|
2021-12-10 22:35:47 +01:00
|
|
|
|
2022-06-07 19:25:14 +02:00
|
|
|
authFailLogin: true,
|
2021-12-10 22:35:47 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "generate token fail",
|
|
|
|
method: http.MethodPost,
|
2022-06-07 19:25:14 +02:00
|
|
|
requestBody: `{"deviceId": "dev-1", "email": "abc@example.com", "password": "123"}`,
|
2021-12-10 22:35:47 +01:00
|
|
|
expectedStatusCode: http.StatusInternalServerError,
|
2021-12-25 02:16:58 +01:00
|
|
|
expectedErrorString: http.StatusText(http.StatusInternalServerError),
|
2021-12-10 22:35:47 +01:00
|
|
|
|
|
|
|
authFailGenToken: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "save token fail",
|
|
|
|
method: http.MethodPost,
|
2022-06-07 19:25:14 +02:00
|
|
|
requestBody: `{"deviceId": "dev-1", "email": "abc@example.com", "password": "123"}`,
|
2021-12-10 22:35:47 +01:00
|
|
|
expectedStatusCode: http.StatusInternalServerError,
|
2021-12-25 02:16:58 +01:00
|
|
|
expectedErrorString: http.StatusText(http.StatusInternalServerError),
|
2021-12-10 22:35:47 +01:00
|
|
|
|
|
|
|
storeFailSave: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
|
|
|
|
// Set this up to fail according to specification
|
2021-12-25 02:16:58 +01:00
|
|
|
testAuth := TestAuth{TestToken: auth.AuthTokenString("seekrit")}
|
2021-12-10 22:35:47 +01:00
|
|
|
testStore := TestStore{}
|
2022-06-07 19:25:14 +02:00
|
|
|
if tc.authFailLogin {
|
|
|
|
testStore.FailLogin = true
|
2021-12-10 22:35:47 +01:00
|
|
|
} else if tc.authFailGenToken {
|
|
|
|
testAuth.FailGenToken = true
|
|
|
|
} else if tc.storeFailSave {
|
|
|
|
testStore.FailSave = true
|
|
|
|
} else {
|
2021-12-25 02:16:58 +01:00
|
|
|
testAuth.TestToken = auth.AuthTokenString("seekrit")
|
2021-12-10 22:35:47 +01:00
|
|
|
}
|
2021-12-25 02:16:58 +01:00
|
|
|
server := Server{&testAuth, &testStore, &wallet.WalletUtil{}}
|
2021-12-10 22:35:47 +01:00
|
|
|
|
|
|
|
// Make request
|
2022-06-08 00:24:01 +02:00
|
|
|
req := httptest.NewRequest(tc.method, PathAuthToken, bytes.NewBuffer([]byte(tc.requestBody)))
|
2021-12-10 22:35:47 +01:00
|
|
|
w := httptest.NewRecorder()
|
|
|
|
|
2022-06-08 00:24:01 +02:00
|
|
|
server.getAuthToken(w, req)
|
2021-12-10 22:35:47 +01:00
|
|
|
|
|
|
|
if want, got := tc.expectedStatusCode, w.Result().StatusCode; want != got {
|
|
|
|
t.Errorf("StatusCode: expected %d, got %d", want, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
body, _ := ioutil.ReadAll(w.Body)
|
|
|
|
|
|
|
|
var result ErrorResponse
|
|
|
|
if err := json.Unmarshal(body, &result); err != nil {
|
|
|
|
t.Fatalf("Error decoding error message %s: `%s`", err, body)
|
|
|
|
}
|
|
|
|
|
|
|
|
if want, got := tc.expectedErrorString, result.Error; want != got {
|
|
|
|
t.Errorf("Error String: expected %s, got %s", want, got)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-08 00:24:01 +02:00
|
|
|
func TestServerValidateAuthRequest(t *testing.T) {
|
2022-06-08 02:08:41 +02:00
|
|
|
authRequest := AuthRequest{DeviceId: "dId", Email: "joe@example.com", Password: "aoeu"}
|
|
|
|
if !authRequest.validate() {
|
|
|
|
t.Fatalf("Expected valid AuthRequest to successfully validate")
|
|
|
|
}
|
|
|
|
|
|
|
|
authRequest = AuthRequest{Email: "joe@example.com", Password: "aoeu"}
|
|
|
|
if authRequest.validate() {
|
|
|
|
t.Fatalf("Expected AuthRequest with missing device to not successfully validate")
|
|
|
|
}
|
|
|
|
|
|
|
|
authRequest = AuthRequest{DeviceId: "dId", Email: "joe-example.com", Password: "aoeu"}
|
|
|
|
if authRequest.validate() {
|
|
|
|
t.Fatalf("Expected AuthRequest with invalid email to not successfully validate")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note that Golang's email address parser, which I use, will accept
|
|
|
|
// "Joe <joe@example.com>" so we need to make sure to avoid accepting it. See
|
|
|
|
// the implementation.
|
|
|
|
authRequest = AuthRequest{DeviceId: "dId", Email: "Joe <joe@example.com>", Password: "aoeu"}
|
|
|
|
if authRequest.validate() {
|
|
|
|
t.Fatalf("Expected AuthRequest with email with unexpected formatting to not successfully validate")
|
|
|
|
}
|
|
|
|
|
|
|
|
authRequest = AuthRequest{DeviceId: "dId", Email: "joe@example.com"}
|
|
|
|
if authRequest.validate() {
|
|
|
|
t.Fatalf("Expected AuthRequest with missing password to not successfully validate")
|
|
|
|
}
|
2021-12-24 04:29:02 +01:00
|
|
|
}
|