diff --git a/server/app/auth.go b/server/app/auth.go index fc1d7b056..043dbc532 100644 --- a/server/app/auth.go +++ b/server/app/auth.go @@ -120,7 +120,7 @@ func createDefaultUser(ctx context.Context, ds model.DataStore, username, passwo UserName: username, Name: strings.Title(username), Email: "", - Password: password, + NewPassword: password, IsAdmin: true, LastLoginAt: &now, } diff --git a/server/app/auth_test.go b/server/app/auth_test.go index 074175992..26f377d3a 100644 --- a/server/app/auth_test.go +++ b/server/app/auth_test.go @@ -1,8 +1,14 @@ package app import ( + "context" + "encoding/json" "net/http" "net/http/httptest" + "strings" + + "github.com/navidrome/navidrome/model" + "github.com/navidrome/navidrome/tests" "github.com/navidrome/navidrome/consts" . "github.com/onsi/ginkgo" @@ -10,6 +16,38 @@ import ( ) var _ = Describe("Auth", func() { + Describe("CreateAdmin", func() { + var ds model.DataStore + var req *http.Request + var resp *httptest.ResponseRecorder + + BeforeEach(func() { + ds = &tests.MockDataStore{} + req = httptest.NewRequest("POST", "/createAdmin", strings.NewReader(`{"username":"johndoe", "password":"secret"}`)) + resp = httptest.NewRecorder() + CreateAdmin(ds)(resp, req) + }) + + It("creates an admin user with the specified password", func() { + usr := ds.User(context.TODO()) + u, err := usr.FindByUsername("johndoe") + Expect(err).To(BeNil()) + Expect(u.Password).ToNot(BeEmpty()) + Expect(u.IsAdmin).To(BeTrue()) + }) + + It("returns the expected payload", func() { + Expect(resp.Code).To(Equal(http.StatusOK)) + var parsed map[string]interface{} + Expect(json.Unmarshal(resp.Body.Bytes(), &parsed)).To(BeNil()) + Expect(parsed["isAdmin"]).To(Equal(true)) + Expect(parsed["username"]).To(Equal("johndoe")) + Expect(parsed["name"]).To(Equal("Johndoe")) + Expect(parsed["id"]).ToNot(BeEmpty()) + Expect(parsed["token"]).ToNot(BeEmpty()) + }) + }) + Describe("mapAuthHeader", func() { It("maps the custom header to Authorization header", func() { r := httptest.NewRequest("GET", "/index.html", nil) diff --git a/tests/mock_persistence.go b/tests/mock_persistence.go index f42f14171..b7bf67e36 100644 --- a/tests/mock_persistence.go +++ b/tests/mock_persistence.go @@ -2,8 +2,6 @@ package tests import ( "context" - "encoding/base64" - "strings" "github.com/navidrome/navidrome/model" ) @@ -14,6 +12,7 @@ type MockDataStore struct { MockedArtist model.ArtistRepository MockedMediaFile model.MediaFileRepository MockedUser model.UserRepository + MockedProperty model.PropertyRepository MockedPlayer model.PlayerRepository MockedTranscoding model.TranscodingRepository } @@ -59,7 +58,10 @@ func (db *MockDataStore) PlayQueue(context.Context) model.PlayQueueRepository { } func (db *MockDataStore) Property(context.Context) model.PropertyRepository { - return struct{ model.PropertyRepository }{} + if db.MockedProperty == nil { + db.MockedProperty = &mockedPropertyRepo{} + } + return db.MockedProperty } func (db *MockDataStore) User(context.Context) model.UserRepository { @@ -94,32 +96,3 @@ func (db *MockDataStore) Resource(ctx context.Context, m interface{}) model.Reso func (db *MockDataStore) GC(ctx context.Context, rootFolder string) error { return nil } - -type mockedUserRepo struct { - model.UserRepository - data map[string]*model.User -} - -func (u *mockedUserRepo) CountAll(qo ...model.QueryOptions) (int64, error) { - return int64(len(u.data)), nil -} - -func (u *mockedUserRepo) Put(usr *model.User) error { - if u.data == nil { - u.data = make(map[string]*model.User) - } - if usr.ID == "" { - usr.ID = base64.StdEncoding.EncodeToString([]byte(usr.UserName)) - } - usr.Password = usr.NewPassword - u.data[strings.ToLower(usr.UserName)] = usr - return nil -} - -func (u *mockedUserRepo) FindByUsername(username string) (*model.User, error) { - usr, ok := u.data[strings.ToLower(username)] - if !ok { - return nil, model.ErrNotFound - } - return usr, nil -} diff --git a/tests/mock_property_repo.go b/tests/mock_property_repo.go new file mode 100644 index 000000000..bfbe9f41c --- /dev/null +++ b/tests/mock_property_repo.go @@ -0,0 +1,47 @@ +package tests + +import "github.com/navidrome/navidrome/model" + +type mockedPropertyRepo struct { + model.UserRepository + data map[string]string + err error +} + +func (p *mockedPropertyRepo) init() { + if p.data == nil { + p.data = make(map[string]string) + } +} + +func (p *mockedPropertyRepo) Put(id string, value string) error { + if p.err != nil { + return p.err + } + p.init() + p.data[id] = value + return nil +} + +func (p *mockedPropertyRepo) Get(id string) (string, error) { + if p.err != nil { + return "", p.err + } + p.init() + if v, ok := p.data[id]; ok { + return v, nil + } + return "", model.ErrNotFound +} + +func (p *mockedPropertyRepo) DefaultGet(id string, defaultValue string) (string, error) { + if p.err != nil { + return "", p.err + } + p.init() + v, err := p.Get(id) + if err != nil { + return defaultValue, nil + } + return v, nil +} diff --git a/tests/mock_user_repo.go b/tests/mock_user_repo.go new file mode 100644 index 000000000..a50968e97 --- /dev/null +++ b/tests/mock_user_repo.go @@ -0,0 +1,41 @@ +package tests + +import ( + "encoding/base64" + "strings" + + "github.com/navidrome/navidrome/model" +) + +type mockedUserRepo struct { + model.UserRepository + data map[string]*model.User +} + +func (u *mockedUserRepo) CountAll(qo ...model.QueryOptions) (int64, error) { + return int64(len(u.data)), nil +} + +func (u *mockedUserRepo) Put(usr *model.User) error { + if u.data == nil { + u.data = make(map[string]*model.User) + } + if usr.ID == "" { + usr.ID = base64.StdEncoding.EncodeToString([]byte(usr.UserName)) + } + usr.Password = usr.NewPassword + u.data[strings.ToLower(usr.UserName)] = usr + return nil +} + +func (u *mockedUserRepo) FindByUsername(username string) (*model.User, error) { + usr, ok := u.data[strings.ToLower(username)] + if !ok { + return nil, model.ErrNotFound + } + return usr, nil +} + +func (u *mockedUserRepo) UpdateLastLoginAt(id string) error { + return nil +}