package subsonic import "testing" func TestCreateUserAndGetUser(t *testing.T) { s, srv := newTestRecorderServer(t) createTestUser(t, s, "admin", "adminpassword1", true) q := baseParams("admin", "adminpassword1") q.Set("username", "newbie") q.Set("password", "newbiepass123") q.Set("email", "newbie@example.com") q.Set("streamRole", "true") q.Set("downloadRole", "false") resp := getPath(t, srv.URL, "/rest/createUser.view", q) x := decodeXML(t, resp) if x.Status != "ok" { t.Fatalf("createUser failed: %+v", x) } q2 := baseParams("admin", "adminpassword1") q2.Set("username", "newbie") q2.Set("f", "json") resp = getPath(t, srv.URL, "/rest/getUser.view", q2) j := decodeJSON(t, resp) u := j["user"].(map[string]any) if u["email"] != "newbie@example.com" { t.Fatalf("email = %v", u["email"]) } if u["streamRole"] != true { t.Fatalf("streamRole = %v, want true", u["streamRole"]) } if u["downloadRole"] != false { t.Fatalf("downloadRole = %v, want false", u["downloadRole"]) } if u["adminRole"] != false { t.Fatalf("adminRole = %v, want false", u["adminRole"]) } // The new user can log in with the password we set. loginQ := baseParams("newbie", "newbiepass123") resp = getPath(t, srv.URL, "/rest/ping.view", loginQ) x = decodeXML(t, resp) if x.Status != "ok" { t.Fatalf("new user login failed: %+v", x) } } func TestGetUserForbiddenForOthers(t *testing.T) { s, srv := newTestRecorderServer(t) createTestUser(t, s, "alice", "password123", false) createTestUser(t, s, "bob", "password123", false) q := baseParams("alice", "password123") q.Set("username", "bob") resp := getPath(t, srv.URL, "/rest/getUser.view", q) x := decodeXML(t, resp) if x.Status != "failed" || x.Error == nil || x.Error.Code != ErrUnauthorized { t.Fatalf("expected error 50, got %+v", x) } } func TestGetUsersRequiresAdmin(t *testing.T) { s, srv := newTestRecorderServer(t) createTestUser(t, s, "alice", "password123", false) resp := getPath(t, srv.URL, "/rest/getUsers.view", baseParams("alice", "password123")) x := decodeXML(t, resp) if x.Status != "failed" || x.Error == nil || x.Error.Code != ErrUnauthorized { t.Fatalf("expected error 50, got %+v", x) } } func TestUpdateUserPreservesUnspecifiedRoles(t *testing.T) { s, srv := newTestRecorderServer(t) createTestUser(t, s, "admin", "adminpassword1", true) q := baseParams("admin", "adminpassword1") q.Set("username", "bob") q.Set("password", "bobpassword12") q.Set("streamRole", "true") q.Set("downloadRole", "true") getPath(t, srv.URL, "/rest/createUser.view", q) q2 := baseParams("admin", "adminpassword1") q2.Set("username", "bob") q2.Set("email", "bob@example.com") // Deliberately omit streamRole/downloadRole to verify they survive. resp := getPath(t, srv.URL, "/rest/updateUser.view", q2) x := decodeXML(t, resp) if x.Status != "ok" { t.Fatalf("updateUser failed: %+v", x) } q3 := baseParams("admin", "adminpassword1") q3.Set("username", "bob") q3.Set("f", "json") resp = getPath(t, srv.URL, "/rest/getUser.view", q3) j := decodeJSON(t, resp) u := j["user"].(map[string]any) if u["streamRole"] != true || u["downloadRole"] != true { t.Fatalf("roles should be preserved across update, got %v", u) } if u["email"] != "bob@example.com" { t.Fatalf("email = %v, want updated", u["email"]) } } func TestChangePasswordSelf(t *testing.T) { s, srv := newTestRecorderServer(t) createTestUser(t, s, "alice", "password123", false) q := baseParams("alice", "password123") q.Set("username", "alice") q.Set("password", "newpassword456") resp := getPath(t, srv.URL, "/rest/changePassword.view", q) x := decodeXML(t, resp) if x.Status != "ok" { t.Fatalf("changePassword failed: %+v", x) } resp = getPath(t, srv.URL, "/rest/ping.view", baseParams("alice", "newpassword456")) x = decodeXML(t, resp) if x.Status != "ok" { t.Fatalf("login with new password failed: %+v", x) } } func TestChangePasswordOtherUserForbidden(t *testing.T) { s, srv := newTestRecorderServer(t) createTestUser(t, s, "alice", "password123", false) createTestUser(t, s, "bob", "password123", false) q := baseParams("alice", "password123") q.Set("username", "bob") q.Set("password", "hacked12345") resp := getPath(t, srv.URL, "/rest/changePassword.view", q) x := decodeXML(t, resp) if x.Status != "failed" || x.Error == nil || x.Error.Code != ErrUnauthorized { t.Fatalf("expected error 50, got %+v", x) } } func TestDeleteUserCannotDeleteSelf(t *testing.T) { s, srv := newTestRecorderServer(t) createTestUser(t, s, "admin", "adminpassword1", true) q := baseParams("admin", "adminpassword1") q.Set("username", "admin") resp := getPath(t, srv.URL, "/rest/deleteUser.view", q) x := decodeXML(t, resp) if x.Status != "failed" { t.Fatalf("expected failure deleting own account, got %+v", x) } }