Prevent admin from seeing all tasks (#477)

* Prevent admin from seeing all tasks

* fixup! Prevent admin from seeing all tasks
This commit is contained in:
Chris 2025-11-04 09:40:33 +02:00 committed by GitHub
parent b8c46e1d0d
commit f5c3bf7e69
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 205 additions and 7 deletions

View file

@ -96,7 +96,7 @@ async function getAccess(userId, resourceType, resourceUid) {
}
async function ownershipOrPermissionWhere(resourceType, userId) {
// Admin users can see all resources
// Build WHERE clause for resource queries based on ownership and sharing permissions
// Note: isAdmin expects a UID, but we might receive a numeric ID
// Get the user's UID if we received a numeric ID
let userUid = userId;
@ -118,12 +118,15 @@ async function ownershipOrPermissionWhere(resourceType, userId) {
`[PERMISSIONS DEBUG] Resource: ${resourceType}, UserId: ${userId}, IsAdmin: ${isUserAdmin}`
);
if (isUserAdmin) {
console.log(
`[PERMISSIONS DEBUG] User is admin, returning empty where clause (all resources visible)`
);
return {}; // empty where clause = no restriction
}
// Admin users should NOT see all resources automatically
// They should only see their own resources and shared resources, like regular users
// If admin-level system-wide visibility is needed, it should be via dedicated admin endpoints
// if (isUserAdmin) {
// console.log(
// `[PERMISSIONS DEBUG] User is admin, returning empty where clause (all resources visible)`
// );
// return {}; // empty where clause = no restriction
// }
const sharedUids = await getSharedUidsForUser(resourceType, userId);
console.log(

View file

@ -0,0 +1,195 @@
const request = require('supertest');
const app = require('../../app');
const { Task, Project, Note, Role } = require('../../models');
const { createTestUser } = require('../helpers/testUtils');
describe('Admin Permissions - Resource Visibility', () => {
let adminUser, regularUser, adminAgent, regularAgent;
async function makeAdmin(userId) {
await Role.findOrCreate({
where: { user_id: userId },
defaults: { user_id: userId, is_admin: true },
});
}
async function loginAgent(email) {
const agent = request.agent(app);
await agent.post('/api/login').send({ email, password: 'password123' });
return agent;
}
beforeEach(async () => {
// Create admin user
adminUser = await createTestUser({
email: `admin_${Date.now()}@example.com`,
});
await makeAdmin(adminUser.id);
// Create regular user
regularUser = await createTestUser({
email: `regular_${Date.now()}@example.com`,
});
// Login both users
adminAgent = await loginAgent(adminUser.email);
regularAgent = await loginAgent(regularUser.email);
});
describe('Tasks visibility', () => {
it('admin should only see their own tasks, not all tasks', async () => {
// Create tasks for both users
const adminTask = await Task.create({
name: 'Admin Task',
user_id: adminUser.id,
});
const regularTask = await Task.create({
name: 'Regular User Task',
user_id: regularUser.id,
});
// Admin fetches all tasks
const res = await adminAgent.get('/api/tasks');
expect(res.status).toBe(200);
const taskIds = res.body.tasks.map((t) => t.id);
// Admin should see their own task
expect(taskIds).toContain(adminTask.id);
// Admin should NOT see other user's task (THIS IS THE KEY FIX)
expect(taskIds).not.toContain(regularTask.id);
});
});
describe('Projects visibility', () => {
it('admin should only see their own projects, not all projects', async () => {
// Create projects for both users
const adminProject = await Project.create({
name: 'Admin Project',
user_id: adminUser.id,
});
const regularProject = await Project.create({
name: 'Regular User Project',
user_id: regularUser.id,
});
// Admin fetches all projects
const res = await adminAgent.get('/api/projects');
expect(res.status).toBe(200);
const projectIds = res.body.projects.map((p) => p.id);
// Admin should see their own project
expect(projectIds).toContain(adminProject.id);
// Admin should NOT see other user's project (THIS IS THE KEY FIX)
expect(projectIds).not.toContain(regularProject.id);
});
});
describe('Notes visibility', () => {
it('admin should only see their own notes, not all notes', async () => {
// Create notes for both users
const adminNote = await Note.create({
name: 'Admin Note',
content: 'Admin content',
user_id: adminUser.id,
});
const regularNote = await Note.create({
name: 'Regular User Note',
content: 'Regular content',
user_id: regularUser.id,
});
// Admin fetches all notes
const res = await adminAgent.get('/api/notes');
expect(res.status).toBe(200);
const noteIds = res.body.map((n) => n.id);
// Admin should see their own note
expect(noteIds).toContain(adminNote.id);
// Admin should NOT see other user's note (THIS IS THE KEY FIX)
expect(noteIds).not.toContain(regularNote.id);
});
});
describe('Regular user behavior unchanged', () => {
it('regular user should only see their own tasks', async () => {
// Create tasks for both users
const adminTask = await Task.create({
name: 'Admin Task',
user_id: adminUser.id,
});
const regularTask = await Task.create({
name: 'Regular User Task',
user_id: regularUser.id,
});
// Regular user fetches all tasks
const res = await regularAgent.get('/api/tasks');
expect(res.status).toBe(200);
const taskIds = res.body.tasks.map((t) => t.id);
// Regular user should see their own task
expect(taskIds).toContain(regularTask.id);
// Regular user should NOT see admin's task
expect(taskIds).not.toContain(adminTask.id);
});
});
describe('Task metrics visibility', () => {
it('admin task metrics should only include own tasks', async () => {
// Create tasks for admin only (to avoid confusion)
const adminTask1 = await Task.create({
name: 'Admin Task 1',
user_id: adminUser.id,
is_completed: false,
});
const adminTask2 = await Task.create({
name: 'Admin Task 2',
user_id: adminUser.id,
is_completed: true,
});
// Create tasks for regular user (should not appear in admin's metrics)
await Task.create({
name: 'Regular Task 1',
user_id: regularUser.id,
is_completed: false,
});
await Task.create({
name: 'Regular Task 2',
user_id: regularUser.id,
is_completed: false,
});
// Admin fetches tasks with metrics
const res = await adminAgent.get('/api/tasks?compute_metrics=true');
expect(res.status).toBe(200);
// Admin should only see their own tasks in the response
expect(res.body.tasks.length).toBe(2);
// Verify the admin's task IDs are present
const taskIds = res.body.tasks.map((t) => t.id);
expect(taskIds).toContain(adminTask1.id);
expect(taskIds).toContain(adminTask2.id);
// Verify metrics exist and only count admin's tasks
expect(res.body.metrics).toBeDefined();
// Admin has 2 tasks total (other users' tasks should not be counted)
expect(res.body.metrics.total_open_tasks).toBeLessThanOrEqual(2);
});
});
});