diff --git a/server/users.go b/server/users.go index 7f4f8cb..73f6b05 100644 --- a/server/users.go +++ b/server/users.go @@ -37,7 +37,7 @@ func (rest *REST) usersRegister(w http.ResponseWriter, r *http.Request) { } func (rest *REST) usersLogin(w http.ResponseWriter, r *http.Request) { - salt := uuid.New().String() + salt := uuid.New().String()[:5] var token string var err error switch config.New().Auth { diff --git a/server/users_test.go b/server/users_test.go index b6145d8..f73506a 100644 --- a/server/users_test.go +++ b/server/users_test.go @@ -1,7 +1,168 @@ package server -import "testing" +import ( + "encoding/json" + "fmt" + "local/dndex/server/auth" + "net/http" + "net/http/httptest" + "strings" + "testing" -func TestUsers(t *testing.T) { - t.Fatal("not impl") + "github.com/google/uuid" +) + +func TestUsersRegister(t *testing.T) { + rest, _, clean := testREST(t) + defer clean() + + t.Run("register ok", func(t *testing.T) { + user := uuid.New().String()[:5] + pwd := uuid.New().String()[:5] + testRegisterOK(t, rest, user, pwd) + }) + + t.Run("register 400: nil body", func(t *testing.T) { + r := httptest.NewRequest(http.MethodPost, "/register", nil) + w := httptest.NewRecorder() + rest.users(w, r) + if w.Code < http.StatusBadRequest { + t.Fatalf("wanted bad, got %v: %s", w.Code, w.Body.Bytes()) + } + }) + + t.Run("register 400: empty", func(t *testing.T) { + r := httptest.NewRequest(http.MethodPost, "/register", strings.NewReader(``)) + w := httptest.NewRecorder() + rest.users(w, r) + if w.Code < http.StatusBadRequest { + t.Fatalf("wanted 400, got %v: %s", w.Code, w.Body.Bytes()) + } + }) + + t.Run("register 400: only ns", func(t *testing.T) { + r := httptest.NewRequest(http.MethodPost, "/register", strings.NewReader(`DnDex-User=`+uuid.New().String())) + w := httptest.NewRecorder() + rest.users(w, r) + if w.Code < http.StatusBadRequest { + t.Fatalf("wanted 400, got %v: %s", w.Code, w.Body.Bytes()) + } + }) + + t.Run("register collision", func(t *testing.T) { + user := uuid.New().String()[:5] + for i := 0; i < 2; i++ { + pwd := uuid.New().String()[:5] + body := fmt.Sprintf(`%s=%s&%s=%s`, auth.UserKey, user, auth.AuthKey, pwd) + r := httptest.NewRequest(http.MethodPost, "/register", strings.NewReader(body)) + r.Header.Set("Content-Type", "application/x-www-form-urlencoded") + w := httptest.NewRecorder() + rest.users(w, r) + if i == 0 { + if w.Code != http.StatusOK { + t.Fatalf("%d: wanted 200, got %v: %s", i, w.Code, w.Body.Bytes()) + } + } else { + if w.Code < http.StatusBadRequest { + t.Fatalf("%d: wanted 400, got %v: %s", i, w.Code, w.Body.Bytes()) + } + } + } + }) +} + +func TestUsersLogin(t *testing.T) { + rest, _, clean := testREST(t) + defer clean() + + t.Run("login ok", func(t *testing.T) { + user := uuid.New().String()[:5] + pwd := uuid.New().String()[:5] + testRegisterOK(t, rest, user, pwd) + testLoginOK(t, rest, user, pwd) + }) + + t.Run("login 404 user", func(t *testing.T) { + pwd := uuid.New().String()[:5] + testLoginNotOK(t, rest, "bad", pwd) + }) + + t.Run("login bad user", func(t *testing.T) { + user := uuid.New().String()[:5] + pwd := uuid.New().String()[:5] + testRegisterOK(t, rest, user, pwd) + testLoginNotOK(t, rest, "bad", pwd) + }) + + t.Run("login bad pwd", func(t *testing.T) { + user := uuid.New().String()[:5] + pwd := uuid.New().String()[:5] + testRegisterOK(t, rest, user, pwd) + testLoginNotOK(t, rest, user, "bad") + }) +} + +func testRegisterOK(t *testing.T, rest *REST, user, pwd string) { + body := fmt.Sprintf(`%s=%s&%s=%s`, auth.UserKey, user, auth.AuthKey, pwd) + r := httptest.NewRequest(http.MethodPost, "/register", strings.NewReader(body)) + r.Header.Set("Content-Type", "application/x-www-form-urlencoded") + w := httptest.NewRecorder() + rest.users(w, r) + if w.Code != http.StatusOK { + t.Fatalf("wanted 200, got %v: %s", w.Code, w.Body.Bytes()) + } +} + +func testLoginNotOK(t *testing.T, rest *REST, user, pwd string) { + body := fmt.Sprintf(`%s=%s`, auth.UserKey, user) + r := httptest.NewRequest(http.MethodPost, "/login", strings.NewReader(body)) + r.Header.Set("Content-Type", "application/x-www-form-urlencoded") + w := httptest.NewRecorder() + rest.users(w, r) + if w.Code < http.StatusBadRequest { + var resp struct { + OK struct { + Salt string `json:"salt"` + Token string `json:"token"` + } + } + if err := json.NewDecoder(w.Body).Decode(&resp); err != nil { + t.Fatal(err) + } + token := auth.Token{} + if err := token.Decode(resp.OK.Salt+pwd, resp.OK.Token); err == nil { + t.Fatal(err, token) + } + } +} + +func testLoginOK(t *testing.T, rest *REST, user, pwd string) string { + body := fmt.Sprintf(`%s=%s`, auth.UserKey, user) + r := httptest.NewRequest(http.MethodPost, "/login", strings.NewReader(body)) + r.Header.Set("Content-Type", "application/x-www-form-urlencoded") + w := httptest.NewRecorder() + rest.users(w, r) + if w.Code != http.StatusOK { + t.Fatalf("wanted 200, got %v: %s", w.Code, w.Body.Bytes()) + } + var resp struct { + OK struct { + Salt string `json:"salt"` + Token string `json:"token"` + } + } + if err := json.NewDecoder(w.Body).Decode(&resp); err != nil { + t.Fatal(err) + } + token := auth.Token{} + if err := token.Decode(resp.OK.Salt+pwd, resp.OK.Token); err != nil { + t.Fatal(err) + } + if token.Namespace != user { + t.Fatal(token.Namespace) + } + if token.ID == "" { + t.Fatal(token.ID) + } + return token.ID }