2021-12-25 02:16:58 +01:00
|
|
|
package server
|
2021-12-10 22:35:47 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
2022-06-19 22:40:16 +02:00
|
|
|
"fmt"
|
2021-12-10 22:35:47 +01:00
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
2022-07-11 15:42:08 +02:00
|
|
|
"strings"
|
2021-12-10 22:35:47 +01:00
|
|
|
"testing"
|
2022-07-13 18:32:48 +02:00
|
|
|
|
2022-08-22 18:05:53 +02:00
|
|
|
"lbryio/wallet-sync-server/auth"
|
|
|
|
"lbryio/wallet-sync-server/server/paths"
|
|
|
|
"lbryio/wallet-sync-server/store"
|
2021-12-10 22:35:47 +01:00
|
|
|
)
|
|
|
|
|
2021-12-19 23:24:43 +01:00
|
|
|
func TestServerAuthHandlerSuccess(t *testing.T) {
|
2022-07-28 01:45:09 +02:00
|
|
|
testAuth := TestAuth{TestNewAuthTokenString: auth.AuthTokenString("seekrit")}
|
2021-12-10 22:35:47 +01:00
|
|
|
testStore := TestStore{}
|
2022-08-27 17:37:09 +02:00
|
|
|
s := Init(&testAuth, &testStore, &TestEnv{}, &TestMail{}, TestPort)
|
2021-12-10 22:35:47 +01:00
|
|
|
|
2022-08-23 01:41:30 +02:00
|
|
|
requestBody := []byte(`{"deviceId": "dev-1", "email": "abc@example.com", "password": "12345678"}`)
|
2021-12-10 22:35:47 +01:00
|
|
|
|
2022-08-01 17:50:16 +02:00
|
|
|
req := httptest.NewRequest(http.MethodPost, paths.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)
|
|
|
|
|
2022-06-21 17:52:03 +02:00
|
|
|
expectStatusCode(t, w, http.StatusOK)
|
2021-12-10 22:35:47 +01:00
|
|
|
|
2022-06-20 00:54:59 +02:00
|
|
|
var result auth.AuthToken
|
2021-12-10 22:35:47 +01:00
|
|
|
err := json.Unmarshal(body, &result)
|
|
|
|
|
2022-07-28 01:45:09 +02:00
|
|
|
if err != nil || result.Token != testAuth.TestNewAuthTokenString {
|
2021-12-10 22:35:47 +01:00
|
|
|
t.Errorf("Expected auth response to contain token: result: %+v err: %+v", string(body), err)
|
|
|
|
}
|
|
|
|
|
2022-07-28 01:45:09 +02:00
|
|
|
if testStore.Called.SaveToken != testAuth.TestNewAuthTokenString {
|
|
|
|
t.Errorf("Expected Store.SaveToken to be called with %s", testAuth.TestNewAuthTokenString)
|
2021-12-10 22:35:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
2022-06-22 17:06:05 +02:00
|
|
|
email string
|
2021-12-10 22:35:47 +01:00
|
|
|
expectedStatusCode int
|
|
|
|
expectedErrorString string
|
|
|
|
|
2022-06-19 22:40:16 +02:00
|
|
|
storeErrors TestStoreFunctionsErrors
|
2021-12-10 22:35:47 +01:00
|
|
|
authFailGenToken bool
|
|
|
|
}{
|
2022-06-22 01:46:10 +02:00
|
|
|
{
|
|
|
|
name: "validation error", // missing email address
|
|
|
|
email: "",
|
|
|
|
expectedStatusCode: http.StatusBadRequest,
|
2022-07-11 15:42:08 +02:00
|
|
|
expectedErrorString: http.StatusText(http.StatusBadRequest) + ": Request failed validation: Invalid 'email'",
|
2022-06-22 01:46:10 +02:00
|
|
|
|
|
|
|
// Just check one validation error (missing email address) to make sure the
|
|
|
|
// validate function is called. We'll check the rest of the validation
|
|
|
|
// errors in the other test below.
|
|
|
|
},
|
2021-12-10 22:35:47 +01:00
|
|
|
{
|
2022-06-19 22:40:16 +02:00
|
|
|
name: "login fail",
|
2022-06-22 01:46:10 +02:00
|
|
|
email: "abc@example.com",
|
2022-06-07 19:25:14 +02:00
|
|
|
expectedStatusCode: http.StatusUnauthorized,
|
2022-07-29 21:52:23 +02:00
|
|
|
expectedErrorString: http.StatusText(http.StatusUnauthorized) + ": No match for email and/or password",
|
2021-12-10 22:35:47 +01:00
|
|
|
|
2022-07-06 18:44:35 +02:00
|
|
|
storeErrors: TestStoreFunctionsErrors{GetUserId: store.ErrWrongCredentials},
|
2021-12-10 22:35:47 +01:00
|
|
|
},
|
2022-07-26 16:53:31 +02:00
|
|
|
{
|
|
|
|
name: "unverified account",
|
|
|
|
email: "abc@example.com",
|
|
|
|
expectedStatusCode: http.StatusUnauthorized,
|
|
|
|
expectedErrorString: http.StatusText(http.StatusUnauthorized) + ": Account is not verified",
|
|
|
|
|
|
|
|
storeErrors: TestStoreFunctionsErrors{GetUserId: store.ErrNotVerified},
|
|
|
|
},
|
2021-12-10 22:35:47 +01:00
|
|
|
{
|
|
|
|
name: "generate token fail",
|
2022-06-22 01:46:10 +02:00
|
|
|
email: "abc@example.com",
|
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",
|
2022-06-22 01:46:10 +02:00
|
|
|
email: "abc@example.com",
|
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
|
|
|
|
2022-06-19 22:40:16 +02:00
|
|
|
storeErrors: TestStoreFunctionsErrors{SaveToken: fmt.Errorf("TestStore.SaveToken fail")},
|
2021-12-10 22:35:47 +01:00
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
|
|
|
|
// Set this up to fail according to specification
|
2022-07-28 01:45:09 +02:00
|
|
|
testAuth := TestAuth{TestNewAuthTokenString: auth.AuthTokenString("seekrit")}
|
2022-06-19 22:40:16 +02:00
|
|
|
testStore := TestStore{Errors: tc.storeErrors}
|
|
|
|
if tc.authFailGenToken { // TODO - TestAuth{Errors:authErrors}
|
2021-12-10 22:35:47 +01:00
|
|
|
testAuth.FailGenToken = true
|
|
|
|
}
|
2022-08-27 17:37:09 +02:00
|
|
|
server := Init(&testAuth, &testStore, &TestEnv{}, &TestMail{}, TestPort)
|
2021-12-10 22:35:47 +01:00
|
|
|
|
|
|
|
// Make request
|
2022-06-19 22:40:16 +02:00
|
|
|
// So long as the JSON is well-formed, the content doesn't matter here since the password check will be stubbed out
|
2022-08-23 01:41:30 +02:00
|
|
|
requestBody := fmt.Sprintf(`{"deviceId": "dev-1", "email": "%s", "password": "12345678"}`, tc.email)
|
2022-08-01 17:50:16 +02:00
|
|
|
req := httptest.NewRequest(http.MethodPost, paths.PathAuthToken, bytes.NewBuffer([]byte(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
|
|
|
|
2022-06-22 17:37:03 +02:00
|
|
|
body, _ := ioutil.ReadAll(w.Body)
|
|
|
|
|
2022-06-21 17:52:03 +02:00
|
|
|
expectStatusCode(t, w, tc.expectedStatusCode)
|
2022-06-22 17:37:03 +02:00
|
|
|
expectErrorString(t, body, tc.expectedErrorString)
|
2021-12-10 22:35:47 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-08 00:24:01 +02:00
|
|
|
func TestServerValidateAuthRequest(t *testing.T) {
|
2022-08-23 01:41:30 +02:00
|
|
|
authRequest := AuthRequest{DeviceId: "dId", Email: "joe@example.com", Password: "12345678"}
|
2022-07-11 15:42:08 +02:00
|
|
|
if authRequest.validate() != nil {
|
2022-07-15 21:36:11 +02:00
|
|
|
t.Errorf("Expected valid AuthRequest to successfully validate")
|
2022-06-08 02:08:41 +02:00
|
|
|
}
|
|
|
|
|
2022-06-22 01:27:54 +02:00
|
|
|
tt := []struct {
|
2022-07-11 15:42:08 +02:00
|
|
|
authRequest AuthRequest
|
|
|
|
expectedErrorSubstr string
|
|
|
|
failureDescription string
|
2022-06-22 01:27:54 +02:00
|
|
|
}{
|
|
|
|
{
|
2022-08-23 01:41:30 +02:00
|
|
|
AuthRequest{Email: "joe@example.com", Password: "12345678"},
|
2022-07-11 15:42:08 +02:00
|
|
|
"deviceId",
|
2022-06-22 01:27:54 +02:00
|
|
|
"Expected AuthRequest with missing device to not successfully validate",
|
|
|
|
}, {
|
2022-08-23 01:41:30 +02:00
|
|
|
AuthRequest{DeviceId: "dId", Email: "joe-example.com", Password: "12345678"},
|
2022-07-11 15:42:08 +02:00
|
|
|
"email",
|
2022-06-22 01:27:54 +02:00
|
|
|
"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.
|
2022-08-23 01:41:30 +02:00
|
|
|
AuthRequest{DeviceId: "dId", Email: "Joe <joe@example.com>", Password: "12345678"},
|
2022-07-11 15:42:08 +02:00
|
|
|
"email",
|
2022-06-22 01:27:54 +02:00
|
|
|
"Expected AuthRequest with email with unexpected formatting to not successfully validate",
|
|
|
|
}, {
|
2022-08-23 01:41:30 +02:00
|
|
|
AuthRequest{DeviceId: "dId", Password: "12345678"},
|
2022-07-11 15:42:08 +02:00
|
|
|
"email",
|
2022-06-22 01:27:54 +02:00
|
|
|
"Expected AuthRequest with missing email to not successfully validate",
|
|
|
|
}, {
|
|
|
|
AuthRequest{DeviceId: "dId", Email: "joe@example.com"},
|
2022-07-11 15:42:08 +02:00
|
|
|
"password",
|
2022-06-22 01:27:54 +02:00
|
|
|
"Expected AuthRequest with missing password to not successfully validate",
|
|
|
|
},
|
2022-06-17 22:15:27 +02:00
|
|
|
}
|
2022-06-22 01:27:54 +02:00
|
|
|
for _, tc := range tt {
|
2022-07-11 15:42:08 +02:00
|
|
|
err := tc.authRequest.validate()
|
|
|
|
if !strings.Contains(err.Error(), tc.expectedErrorSubstr) {
|
2022-06-22 01:27:54 +02:00
|
|
|
t.Errorf(tc.failureDescription)
|
|
|
|
}
|
2022-06-08 02:08:41 +02:00
|
|
|
}
|
2021-12-24 04:29:02 +01:00
|
|
|
}
|