Skip to content

Commit fccdd29

Browse files
carfeiixuwei-fit2cloud
authored andcommitted
Add per-user ownership check to dashboard load/update/delete
Dashboard resource endpoints (load_resource, update_resource, update_canvas, delete_resource) fetched a core_dashboard row by id alone, with no check that the caller created it. The only gating decorator verified workspace membership, not per-user ownership, so any authenticated workspace member could read, rename, or delete any other member's dashboard by id. list_resource already filters by create_by, showing dashboards are meant to be private per creator; this adds the same check to the other four code paths.
1 parent d4ddf6d commit fccdd29

2 files changed

Lines changed: 17 additions & 2 deletions

File tree

backend/apps/dashboard/api/dashboard_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ async def list_resource_api(session: SessionDep, dashboard: QueryDashboard, curr
2222
@router.post("/load_resource", summary=f"{PLACEHOLDER_PREFIX}load_resource_api")
2323
@require_permissions(permission=SqlbotPermission(type='dashboard', keyExpression="dashboard.id"))
2424
async def load_resource_api(session: SessionDep, current_user: CurrentUser, dashboard: QueryDashboard):
25-
return load_resource(session=session, dashboard=dashboard)
25+
return load_resource(session=session, dashboard=dashboard, current_user=current_user)
2626

2727

2828
@router.post("/create_resource", response_model=BaseDashboard, summary=f"{PLACEHOLDER_PREFIX}create_resource_api")

backend/apps/dashboard/crud/dashboard_service.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def list_resource(session: SessionDep, dashboard: QueryDashboard, current_user:
3434
return tree
3535

3636

37-
def load_resource(session: SessionDep, dashboard: QueryDashboard):
37+
def load_resource(session: SessionDep, dashboard: QueryDashboard, current_user: CurrentUser):
3838
sql = text("""
3939
SELECT cd.*,
4040
creator.name AS create_name,
@@ -47,6 +47,11 @@ def load_resource(session: SessionDep, dashboard: QueryDashboard):
4747
""")
4848
result = session.execute(sql, {"dashboard_id": dashboard.id}).mappings().first()
4949

50+
if not result:
51+
raise ValueError(f"Resource with id {dashboard.id} does not exist")
52+
if str(result['create_by']) != str(current_user.id):
53+
raise ValueError(f"Resource with id {dashboard.id} not owned by the current user")
54+
5055
result_dict = dict(result)
5156
canvas_view_obj = orjson.loads(result_dict['canvas_view_info'])
5257
for item in canvas_view_obj.values():
@@ -80,6 +85,10 @@ def create_resource(session: SessionDep, user: CurrentUser, dashboard: CreateDas
8085

8186
def update_resource(session: SessionDep, user: CurrentUser, dashboard: QueryDashboard):
8287
record = session.query(CoreDashboard).filter(CoreDashboard.id == dashboard.id).first()
88+
if not record:
89+
raise ValueError(f"Resource with id {dashboard.id} does not exist")
90+
if str(record.create_by) != str(user.id):
91+
raise ValueError(f"Resource with id {dashboard.id} not owned by the current user")
8392
record.name = dashboard.name
8493
record.update_by = user.id
8594
record.update_time = int(time.time())
@@ -103,6 +112,10 @@ def create_canvas(session: SessionDep, user: CurrentUser, dashboard: CreateDashb
103112

104113
def update_canvas(session: SessionDep, user: CurrentUser, dashboard: CreateDashboard):
105114
record = session.query(CoreDashboard).filter(CoreDashboard.id == dashboard.id).first()
115+
if not record:
116+
raise ValueError(f"Resource with id {dashboard.id} does not exist")
117+
if str(record.create_by) != str(user.id):
118+
raise ValueError(f"Resource with id {dashboard.id} not owned by the current user")
106119
record.name = dashboard.name
107120
record.update_by = user.id
108121
record.update_time = int(time.time())
@@ -149,6 +162,8 @@ def delete_resource(session: SessionDep, current_user: CurrentUser, resource_id:
149162
coreDashboard = session.get(CoreDashboard, resource_id)
150163
if not coreDashboard:
151164
raise ValueError(f"Resource with id {resource_id} does not exist")
165+
if str(coreDashboard.create_by) != str(current_user.id):
166+
raise ValueError(f"Resource with id {resource_id} not owned by the current user")
152167
sql = text("DELETE FROM core_dashboard WHERE id = :resource_id")
153168
result = session.execute(sql, {"resource_id": resource_id})
154169
session.commit()

0 commit comments

Comments
 (0)