This commit is contained in:
+77
-1
@@ -90,7 +90,7 @@ func TestBootstrapAdminAndForcePasswordChange(t *testing.T) {
|
||||
if err := app.db.First(&admin, 1).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if admin.Username != "admin" || !admin.MustChangePassword || !admin.CanManageUsers || !admin.CanAdvancedUpload {
|
||||
if admin.Username != "admin" || !admin.MustChangePassword || !admin.CanManageUsers || !admin.CanManageFiles || !admin.CanAdvancedUpload {
|
||||
t.Fatalf("unexpected admin: %+v", admin)
|
||||
}
|
||||
if bcrypt.CompareHashAndPassword([]byte(admin.PasswordHash), []byte(password)) != nil {
|
||||
@@ -113,6 +113,25 @@ func TestBootstrapAdminAndForcePasswordChange(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureAdminRestoresAllPermissions(t *testing.T) {
|
||||
app, _ := testApp(t)
|
||||
if err := app.db.Model(&User{}).Where("id = ?", 1).Updates(map[string]any{
|
||||
"can_manage_users": false, "can_manage_files": false, "can_upload": false, "can_advanced_upload": false,
|
||||
}).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if password, err := app.ensureAdmin(); err != nil || password != "" {
|
||||
t.Fatalf("ensure admin: password = %q, err = %v", password, err)
|
||||
}
|
||||
var admin User
|
||||
if err := app.db.First(&admin, 1).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !admin.CanManageUsers || !admin.CanManageFiles || !admin.CanUpload || !admin.CanAdvancedUpload {
|
||||
t.Fatalf("admin permissions were not restored: %+v", admin)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPickupCodePreviewConsumesFinalAccessAndDeletesFile(t *testing.T) {
|
||||
app, _ := testApp(t)
|
||||
hash, _ := bcrypt.GenerateFromPassword([]byte("password-123"), bcrypt.DefaultCost)
|
||||
@@ -295,6 +314,58 @@ func TestCleanupRemovesExpiredFileFromDatabaseAndDisk(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileManagementRequiresPermissionAndDeletesFile(t *testing.T) {
|
||||
app, _ := testApp(t)
|
||||
passwordHash, _ := bcrypt.GenerateFromPassword([]byte("password-123"), bcrypt.DefaultCost)
|
||||
owner := User{Username: "file-owner", PasswordHash: string(passwordHash), CanUpload: true}
|
||||
manager := User{Username: "file-manager", PasswordHash: string(passwordHash), CanManageFiles: true}
|
||||
viewer := User{Username: "no-file-access", PasswordHash: string(passwordHash), CanManageUsers: true}
|
||||
for _, user := range []*User{&owner, &manager, &viewer} {
|
||||
if err := app.db.Create(user).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
expires := time.Now().Add(time.Hour)
|
||||
max := 3
|
||||
file := SharedFile{Hash: "managed1", OriginalName: "managed.txt", MimeType: "text/plain", Size: 7, OwnerID: owner.ID, ExpiresAt: &expires, MaxDownloads: &max, Ready: true}
|
||||
if err := app.db.Create(&file).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
path := filepath.Join(app.filesDir, file.Hash)
|
||||
if err := os.WriteFile(path, []byte("managed"), 0o640); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
router := app.router()
|
||||
|
||||
viewerCookie := loginAs(t, router, viewer.Username, "password-123")
|
||||
denied := request(t, router, http.MethodGet, "/api/files", nil, "", viewerCookie)
|
||||
if denied.Code != http.StatusForbidden {
|
||||
t.Fatalf("list without permission status = %d", denied.Code)
|
||||
}
|
||||
denied = request(t, router, http.MethodDelete, "/api/files/"+jsonNumber(file.ID), nil, "", viewerCookie)
|
||||
if denied.Code != http.StatusForbidden {
|
||||
t.Fatalf("delete without permission status = %d", denied.Code)
|
||||
}
|
||||
|
||||
managerCookie := loginAs(t, router, manager.Username, "password-123")
|
||||
listed := request(t, router, http.MethodGet, "/api/files", nil, "", managerCookie)
|
||||
if listed.Code != http.StatusOK || !strings.Contains(listed.Body.String(), owner.Username) || !strings.Contains(listed.Body.String(), file.Hash) {
|
||||
t.Fatalf("list files status = %d, body = %s", listed.Code, listed.Body.String())
|
||||
}
|
||||
deleted := request(t, router, http.MethodDelete, "/api/files/"+jsonNumber(file.ID), nil, "", managerCookie)
|
||||
if deleted.Code != http.StatusNoContent {
|
||||
t.Fatalf("delete file status = %d, body = %s", deleted.Code, deleted.Body.String())
|
||||
}
|
||||
var count int64
|
||||
app.db.Model(&SharedFile{}).Where("id = ?", file.ID).Count(&count)
|
||||
if count != 0 {
|
||||
t.Fatal("deleted file record remains")
|
||||
}
|
||||
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
||||
t.Fatal("deleted file remains on disk")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBasicUploadLimitAndAdvancedInheritance(t *testing.T) {
|
||||
app, _ := testApp(t)
|
||||
passwordHash, _ := bcrypt.GenerateFromPassword([]byte("password-123"), bcrypt.DefaultCost)
|
||||
@@ -380,6 +451,11 @@ func TestUserManagerCannotGrantOrTakeOverPermissionsTheyDoNotHave(t *testing.T)
|
||||
if created.Code != http.StatusForbidden {
|
||||
t.Fatalf("create advanced user status = %d, body = %s", created.Code, created.Body.String())
|
||||
}
|
||||
createBody, _ = json.Marshal(map[string]any{"username": "file-admin", "canManageFiles": true})
|
||||
created = request(t, router, http.MethodPost, "/api/users", bytes.NewReader(createBody), "application/json", cookie)
|
||||
if created.Code != http.StatusForbidden {
|
||||
t.Fatalf("grant file management status = %d, body = %s", created.Code, created.Body.String())
|
||||
}
|
||||
|
||||
updateBody, _ := json.Marshal(map[string]any{"username": basicUser.Username, "canUpload": true, "canAdvancedUpload": true})
|
||||
updated := request(t, router, http.MethodPut, "/api/users/"+jsonNumber(basicUser.ID), bytes.NewReader(updateBody), "application/json", cookie)
|
||||
|
||||
Reference in New Issue
Block a user