| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585 |
- package permission
- import (
- "encoding/json"
- "net/http"
- "net/http/httptest"
- "net/url"
- "path/filepath"
- "strings"
- "testing"
- db "imuslab.com/arozos/mod/database"
- )
- func openTempDB(t *testing.T) *db.Database {
- t.Helper()
- dir := t.TempDir()
- database, err := db.NewDatabase(filepath.Join(dir, "test.db"), false)
- if err != nil {
- t.Fatalf("failed to open test database: %v", err)
- }
- return database
- }
- func TestNewPermissionHandler(t *testing.T) {
- database := openTempDB(t)
- ph, err := NewPermissionHandler(database)
- if err != nil {
- t.Fatalf("NewPermissionHandler error: %v", err)
- }
- if ph == nil {
- t.Fatal("NewPermissionHandler returned nil handler")
- }
- }
- func TestNewPermissionGroup(t *testing.T) {
- database := openTempDB(t)
- ph, _ := NewPermissionHandler(database)
- pg := ph.NewPermissionGroup("editors", false, 500, []string{"filemanager"}, "Desktop")
- if pg == nil {
- t.Fatal("NewPermissionGroup returned nil")
- }
- if pg.Name != "editors" {
- t.Errorf("expected name 'editors', got %q", pg.Name)
- }
- if pg.IsAdmin {
- t.Error("expected IsAdmin=false")
- }
- if pg.DefaultStorageQuota != 500 {
- t.Errorf("expected DefaultStorageQuota=500, got %d", pg.DefaultStorageQuota)
- }
- }
- func TestGroupExists(t *testing.T) {
- database := openTempDB(t)
- ph, _ := NewPermissionHandler(database)
- ph.NewPermissionGroup("writers", false, 0, []string{}, "Desktop")
- if !ph.GroupExists("writers") {
- t.Error("expected GroupExists('writers')=true")
- }
- if ph.GroupExists("nonexistent") {
- t.Error("expected GroupExists('nonexistent')=false")
- }
- }
- func TestGroupExists_CaseInsensitive(t *testing.T) {
- database := openTempDB(t)
- ph, _ := NewPermissionHandler(database)
- ph.NewPermissionGroup("Admins", true, -1, []string{"*"}, "Desktop")
- if !ph.GroupExists("admins") {
- t.Error("GroupExists should be case-insensitive")
- }
- }
- func TestGetPermissionGroupByName(t *testing.T) {
- database := openTempDB(t)
- ph, _ := NewPermissionHandler(database)
- ph.NewPermissionGroup("viewers", false, 100, []string{"gallery"}, "Desktop")
- pg := ph.GetPermissionGroupByName("viewers")
- if pg == nil {
- t.Fatal("GetPermissionGroupByName returned nil for existing group")
- }
- if pg.Name != "viewers" {
- t.Errorf("expected 'viewers', got %q", pg.Name)
- }
- if ph.GetPermissionGroupByName("ghost") != nil {
- t.Error("expected nil for non-existing group")
- }
- }
- func TestGetPermissionGroupByNameList(t *testing.T) {
- database := openTempDB(t)
- ph, _ := NewPermissionHandler(database)
- ph.NewPermissionGroup("alpha", false, 0, []string{}, "Desktop")
- ph.NewPermissionGroup("beta", false, 0, []string{}, "Desktop")
- ph.NewPermissionGroup("gamma", false, 0, []string{}, "Desktop")
- results := ph.GetPermissionGroupByNameList([]string{"alpha", "gamma"})
- if len(results) != 2 {
- t.Errorf("expected 2 groups, got %d", len(results))
- }
- }
- func TestUpdatePermissionGroup(t *testing.T) {
- database := openTempDB(t)
- ph, _ := NewPermissionHandler(database)
- ph.NewPermissionGroup("test-group", false, 200, []string{"mod1"}, "Desktop")
- err := ph.UpdatePermissionGroup("test-group", true, 999, []string{"mod1", "mod2"}, "Mobile")
- if err != nil {
- t.Fatalf("UpdatePermissionGroup error: %v", err)
- }
- pg := ph.GetPermissionGroupByName("test-group")
- if pg == nil {
- t.Fatal("group not found after update")
- }
- if !pg.IsAdmin {
- t.Error("expected IsAdmin=true after update")
- }
- if pg.DefaultStorageQuota != 999 {
- t.Errorf("expected DefaultStorageQuota=999, got %d", pg.DefaultStorageQuota)
- }
- }
- func TestUpdatePermissionGroup_NonExistent(t *testing.T) {
- database := openTempDB(t)
- ph, _ := NewPermissionHandler(database)
- err := ph.UpdatePermissionGroup("ghost-group", false, 0, []string{}, "Desktop")
- if err == nil {
- t.Error("expected error when updating non-existent group")
- }
- }
- func TestAddAndRemoveModule(t *testing.T) {
- database := openTempDB(t)
- ph, _ := NewPermissionHandler(database)
- pg := ph.NewPermissionGroup("modtest", false, 0, []string{}, "Desktop")
- pg.AddModule("filemanager")
- if len(pg.AccessibleModules) != 1 || pg.AccessibleModules[0] != "filemanager" {
- t.Errorf("expected [filemanager], got %v", pg.AccessibleModules)
- }
- // Adding same module twice should be idempotent
- pg.AddModule("filemanager")
- if len(pg.AccessibleModules) != 1 {
- t.Errorf("duplicate AddModule should be no-op, got %v", pg.AccessibleModules)
- }
- pg.RemoveModule("filemanager")
- if len(pg.AccessibleModules) != 0 {
- t.Errorf("expected empty modules after remove, got %v", pg.AccessibleModules)
- }
- }
- func TestGetLargestStorageQuotaFromGroups(t *testing.T) {
- groups := []*PermissionGroup{
- {DefaultStorageQuota: 100},
- {DefaultStorageQuota: 500},
- {DefaultStorageQuota: 200},
- }
- quota := GetLargestStorageQuotaFromGroups(groups)
- if quota != 500 {
- t.Errorf("expected largest quota=500, got %d", quota)
- }
- }
- func TestGetLargestStorageQuotaFromGroups_Unlimited(t *testing.T) {
- groups := []*PermissionGroup{
- {DefaultStorageQuota: 100},
- {DefaultStorageQuota: -1}, // unlimited
- }
- quota := GetLargestStorageQuotaFromGroups(groups)
- if quota != -1 {
- t.Errorf("expected -1 (unlimited), got %d", quota)
- }
- }
- // ----- group.go: Remove -----
- func TestPermissionGroupRemove(t *testing.T) {
- database := openTempDB(t)
- ph, _ := NewPermissionHandler(database)
- pg := ph.NewPermissionGroup("to-remove", false, 0, []string{"mod1"}, "Desktop")
- if !ph.GroupExists("to-remove") {
- t.Fatal("group should exist before Remove")
- }
- pg.Remove()
- // Verify database keys are gone
- if database.KeyExists("permission", "group/to-remove") {
- t.Error("group/to-remove key should be deleted after Remove")
- }
- if database.KeyExists("permission", "isadmin/to-remove") {
- t.Error("isadmin/to-remove key should be deleted after Remove")
- }
- }
- // ----- permission.go: GetUsersPermissionGroup -----
- func TestGetUsersPermissionGroup(t *testing.T) {
- database := openTempDB(t)
- ph, _ := NewPermissionHandler(database)
- ph.NewPermissionGroup("readers", false, 100, []string{"gallery"}, "Desktop")
- ph.NewPermissionGroup("writers", false, 200, []string{"editor"}, "Desktop")
- // Write user -> group mapping into "auth" table (the format used by the system).
- // database.Write JSON-encodes the value, so pass the slice directly.
- err := database.NewTable("auth")
- if err != nil {
- t.Fatalf("NewTable auth: %v", err)
- }
- groups := []string{"readers", "writers"}
- database.Write("auth", "group/alice", groups)
- result, err := ph.GetUsersPermissionGroup("alice")
- if err != nil {
- t.Fatalf("GetUsersPermissionGroup error: %v", err)
- }
- if len(result) != 2 {
- t.Errorf("expected 2 groups for alice, got %d", len(result))
- }
- }
- func TestGetUsersPermissionGroup_UserNotFound(t *testing.T) {
- database := openTempDB(t)
- ph, _ := NewPermissionHandler(database)
- // Ensure the "auth" table exists so the database read doesn't panic on a
- // missing bucket. When the user key is absent the read returns an empty
- // slice with no error; GetUsersPermissionGroup should therefore return an
- // empty result with no error.
- database.NewTable("auth")
- result, err := ph.GetUsersPermissionGroup("ghost")
- if err != nil {
- t.Errorf("unexpected error for unknown user: %v", err)
- }
- if len(result) != 0 {
- t.Errorf("expected empty group list for unknown user, got %d groups", len(result))
- }
- }
- // ----- request.go: HandleListGroup -----
- func newPermHandler(t *testing.T) *PermissionHandler {
- t.Helper()
- database := openTempDB(t)
- ph, err := NewPermissionHandler(database)
- if err != nil {
- t.Fatalf("NewPermissionHandler: %v", err)
- }
- ph.NewPermissionGroup("editors", false, 500, []string{"filemanager"}, "Desktop")
- ph.NewPermissionGroup("admins", true, -1, []string{"*"}, "Desktop")
- return ph
- }
- func TestHandleListGroup_NamesOnly(t *testing.T) {
- ph := newPermHandler(t)
- req := httptest.NewRequest(http.MethodGet, "/api/listgroup", nil)
- rr := httptest.NewRecorder()
- ph.HandleListGroup(rr, req)
- if rr.Code != http.StatusOK {
- t.Fatalf("expected 200, got %d", rr.Code)
- }
- body := rr.Body.String()
- if !strings.Contains(body, "editors") {
- t.Errorf("response should contain 'editors', got: %s", body)
- }
- if !strings.Contains(body, "admins") {
- t.Errorf("response should contain 'admins', got: %s", body)
- }
- }
- func TestHandleListGroup_WithPermissions(t *testing.T) {
- ph := newPermHandler(t)
- req := httptest.NewRequest(http.MethodGet, "/api/listgroup?showper=true", nil)
- rr := httptest.NewRecorder()
- ph.HandleListGroup(rr, req)
- if rr.Code != http.StatusOK {
- t.Fatalf("expected 200, got %d", rr.Code)
- }
- body := rr.Body.String()
- if !strings.Contains(body, "editors") {
- t.Errorf("response should contain group info with 'editors', got: %s", body)
- }
- }
- // ----- request.go: HandleGroupEdit -----
- func postRequest(path string, params map[string]string) *http.Request {
- form := url.Values{}
- for k, v := range params {
- form.Set(k, v)
- }
- req := httptest.NewRequest(http.MethodPost, path, strings.NewReader(form.Encode()))
- req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
- return req
- }
- func TestHandleGroupEdit_ListMode(t *testing.T) {
- ph := newPermHandler(t)
- req := httptest.NewRequest(http.MethodGet, "/api/groupedit?list=true", nil)
- q := req.URL.Query()
- q.Set("list", "true")
- req.URL.RawQuery = q.Encode()
- // PostPara for groupname - use form body
- form := url.Values{}
- form.Set("groupname", "editors")
- req2, _ := http.NewRequest(http.MethodPost, "/api/groupedit?list=true", strings.NewReader(form.Encode()))
- req2.Header.Set("Content-Type", "application/x-www-form-urlencoded")
- rr := httptest.NewRecorder()
- ph.HandleGroupEdit(rr, req2)
- if rr.Code != http.StatusOK {
- t.Fatalf("expected 200, got %d: %s", rr.Code, rr.Body.String())
- }
- body := rr.Body.String()
- if !strings.Contains(body, "editors") {
- t.Errorf("expected group info for 'editors', got: %s", body)
- }
- }
- func TestHandleGroupEdit_ListMode_NonExistentGroup(t *testing.T) {
- ph := newPermHandler(t)
- form := url.Values{}
- form.Set("groupname", "nonexistent")
- req, _ := http.NewRequest(http.MethodPost, "/api/groupedit?list=true", strings.NewReader(form.Encode()))
- req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
- rr := httptest.NewRecorder()
- ph.HandleGroupEdit(rr, req)
- body := rr.Body.String()
- if !strings.Contains(body, "error") {
- t.Errorf("expected error response for non-existent group, got: %s", body)
- }
- }
- func TestHandleGroupEdit_UpdateMode(t *testing.T) {
- ph := newPermHandler(t)
- modList, _ := json.Marshal([]string{"filemanager", "settings"})
- req := postRequest("/api/groupedit", map[string]string{
- "groupname": "editors",
- "permission": string(modList),
- "isAdmin": "false",
- "defaultQuota": "2048",
- "interfaceModule": "Desktop",
- })
- rr := httptest.NewRecorder()
- ph.HandleGroupEdit(rr, req)
- body := rr.Body.String()
- if strings.Contains(body, "error") {
- t.Errorf("unexpected error: %s", body)
- }
- // Verify update took effect
- pg := ph.GetPermissionGroupByName("editors")
- if pg == nil {
- t.Fatal("group 'editors' not found after edit")
- }
- if pg.DefaultStorageQuota != 2048 {
- t.Errorf("expected quota 2048, got %d", pg.DefaultStorageQuota)
- }
- }
- func TestHandleGroupEdit_MissingGroupname(t *testing.T) {
- ph := newPermHandler(t)
- req := postRequest("/api/groupedit", map[string]string{})
- rr := httptest.NewRecorder()
- ph.HandleGroupEdit(rr, req)
- body := rr.Body.String()
- if !strings.Contains(body, "error") {
- t.Errorf("expected error when groupname missing, got: %s", body)
- }
- }
- func TestHandleGroupEdit_CannotUnsetAdminFromAdministrator(t *testing.T) {
- ph := newPermHandler(t)
- // Create the administrator group
- ph.NewPermissionGroup("administrator", true, -1, []string{"*"}, "Desktop")
- modList, _ := json.Marshal([]string{"*"})
- req := postRequest("/api/groupedit", map[string]string{
- "groupname": "administrator",
- "permission": string(modList),
- "isAdmin": "false", // trying to remove admin
- "defaultQuota": "-1",
- "interfaceModule": "Desktop",
- })
- rr := httptest.NewRecorder()
- ph.HandleGroupEdit(rr, req)
- body := rr.Body.String()
- if !strings.Contains(body, "error") {
- t.Errorf("expected error when unsetting admin from administrator, got: %s", body)
- }
- }
- func TestHandleGroupEdit_InvalidPermissionJSON(t *testing.T) {
- ph := newPermHandler(t)
- req := postRequest("/api/groupedit", map[string]string{
- "groupname": "editors",
- "permission": "not-valid-json",
- })
- rr := httptest.NewRecorder()
- ph.HandleGroupEdit(rr, req)
- body := rr.Body.String()
- if !strings.Contains(body, "error") {
- t.Errorf("expected error for invalid JSON permission, got: %s", body)
- }
- }
- // ----- request.go: HandleGroupCreate -----
- func TestHandleGroupCreate_Success(t *testing.T) {
- ph := newPermHandler(t)
- modList, _ := json.Marshal([]string{"gallery"})
- req := postRequest("/api/groupcreate", map[string]string{
- "groupname": "newgroup",
- "permission": string(modList),
- "isAdmin": "false",
- "defaultQuota": "1024",
- "interfaceModule": "Desktop",
- })
- rr := httptest.NewRecorder()
- ph.HandleGroupCreate(rr, req)
- body := rr.Body.String()
- if strings.Contains(body, "error") {
- t.Errorf("unexpected error creating group: %s", body)
- }
- if !ph.GroupExists("newgroup") {
- t.Error("group 'newgroup' should exist after create")
- }
- }
- func TestHandleGroupCreate_DuplicateGroup(t *testing.T) {
- ph := newPermHandler(t)
- modList, _ := json.Marshal([]string{})
- req := postRequest("/api/groupcreate", map[string]string{
- "groupname": "editors", // already exists
- "permission": string(modList),
- "isAdmin": "false",
- "defaultQuota": "0",
- "interfaceModule": "Desktop",
- })
- rr := httptest.NewRecorder()
- ph.HandleGroupCreate(rr, req)
- body := rr.Body.String()
- if !strings.Contains(body, "error") {
- t.Errorf("expected error for duplicate group, got: %s", body)
- }
- }
- func TestHandleGroupCreate_MissingGroupname(t *testing.T) {
- ph := newPermHandler(t)
- req := postRequest("/api/groupcreate", map[string]string{})
- rr := httptest.NewRecorder()
- ph.HandleGroupCreate(rr, req)
- body := rr.Body.String()
- if !strings.Contains(body, "error") {
- t.Errorf("expected error for missing groupname, got: %s", body)
- }
- }
- func TestHandleGroupCreate_InvalidQuota(t *testing.T) {
- ph := newPermHandler(t)
- modList, _ := json.Marshal([]string{})
- req := postRequest("/api/groupcreate", map[string]string{
- "groupname": "quotagroup",
- "permission": string(modList),
- "isAdmin": "false",
- "defaultQuota": "notanumber",
- "interfaceModule": "Desktop",
- })
- rr := httptest.NewRecorder()
- ph.HandleGroupCreate(rr, req)
- body := rr.Body.String()
- if !strings.Contains(body, "error") {
- t.Errorf("expected error for invalid quota, got: %s", body)
- }
- }
- func TestHandleGroupCreate_NegativeQuota(t *testing.T) {
- ph := newPermHandler(t)
- modList, _ := json.Marshal([]string{})
- req := postRequest("/api/groupcreate", map[string]string{
- "groupname": "badquota",
- "permission": string(modList),
- "isAdmin": "false",
- "defaultQuota": "-2", // -1 is unlimited, -2 is invalid
- "interfaceModule": "Desktop",
- })
- rr := httptest.NewRecorder()
- ph.HandleGroupCreate(rr, req)
- body := rr.Body.String()
- if !strings.Contains(body, "error") {
- t.Errorf("expected error for quota < -1, got: %s", body)
- }
- }
- // ----- request.go: HandleGroupRemove -----
- func TestHandleGroupRemove_Success(t *testing.T) {
- ph := newPermHandler(t)
- // Add a removable group
- ph.NewPermissionGroup("temp-group", false, 0, []string{}, "Desktop")
- req := postRequest("/api/groupremove", map[string]string{
- "groupname": "temp-group",
- })
- rr := httptest.NewRecorder()
- ph.HandleGroupRemove(rr, req)
- body := rr.Body.String()
- if strings.Contains(body, "error") {
- t.Errorf("unexpected error removing group: %s", body)
- }
- if ph.GroupExists("temp-group") {
- t.Error("group 'temp-group' should be gone after remove")
- }
- }
- func TestHandleGroupRemove_NonExistentGroup(t *testing.T) {
- ph := newPermHandler(t)
- req := postRequest("/api/groupremove", map[string]string{
- "groupname": "doesnotexist",
- })
- rr := httptest.NewRecorder()
- ph.HandleGroupRemove(rr, req)
- body := rr.Body.String()
- if !strings.Contains(body, "error") {
- t.Errorf("expected error for non-existent group, got: %s", body)
- }
- }
- func TestHandleGroupRemove_CannotRemoveAdministrator(t *testing.T) {
- ph := newPermHandler(t)
- ph.NewPermissionGroup("administrator", true, -1, []string{"*"}, "Desktop")
- req := postRequest("/api/groupremove", map[string]string{
- "groupname": "administrator",
- })
- rr := httptest.NewRecorder()
- ph.HandleGroupRemove(rr, req)
- body := rr.Body.String()
- if !strings.Contains(body, "error") {
- t.Errorf("expected error when trying to remove administrator group, got: %s", body)
- }
- }
- func TestHandleGroupRemove_MissingGroupname(t *testing.T) {
- ph := newPermHandler(t)
- req := postRequest("/api/groupremove", map[string]string{})
- rr := httptest.NewRecorder()
- ph.HandleGroupRemove(rr, req)
- body := rr.Body.String()
- if !strings.Contains(body, "error") {
- t.Errorf("expected error for missing groupname, got: %s", body)
- }
- }
|