fix: security and UX improvements for notifications and shares
- Add ownership checks on all notification and share routes (403 Forbidden) - Validate permission field (only view/edit/admin allowed) - Remove user_id from POST notifications (only self-notifications) - Add getNotification/getProjectShare to DB interface + adapter - Add res.ok checks on all frontend API calls - Add click-outside handler for notification dropdown - Add initial notification load on mount for badge count - Add email validation + duplicate check in ShareDialog - Add Enter key handler in ShareDialog - Add submitting state to prevent double-click - Guard against null token in Dashboard
This commit is contained in:
@@ -404,10 +404,10 @@ export async function getNotifications(token: string): Promise<NotificationItem[
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export async function createNotification(token: string, data: { type?: string; title: string; message: string; user_id?: string }): Promise<NotificationItem> {
|
||||
export async function createNotification(token: string, data: { type?: string; title: string; message: string }): Promise<NotificationItem> {
|
||||
const res = await fetch(`${API_BASE}/api/notifications`, {
|
||||
method: 'POST',
|
||||
headers: authHeaders(token),
|
||||
headers: { ...authHeaders(token), 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
if (!res.ok) throw new Error('Failed to create notification');
|
||||
@@ -415,17 +415,19 @@ export async function createNotification(token: string, data: { type?: string; t
|
||||
}
|
||||
|
||||
export async function markNotificationRead(token: string, id: string): Promise<void> {
|
||||
await fetch(`${API_BASE}/api/notifications/${id}/read`, {
|
||||
const res = await fetch(`${API_BASE}/api/notifications/${id}/read`, {
|
||||
method: 'PATCH',
|
||||
headers: authHeaders(token),
|
||||
});
|
||||
if (!res.ok) throw new Error('Failed to mark notification as read');
|
||||
}
|
||||
|
||||
export async function deleteNotification(token: string, id: string): Promise<void> {
|
||||
await fetch(`${API_BASE}/api/notifications/${id}`, {
|
||||
const res = await fetch(`${API_BASE}/api/notifications/${id}`, {
|
||||
method: 'DELETE',
|
||||
headers: authHeaders(token),
|
||||
});
|
||||
if (!res.ok) throw new Error('Failed to delete notification');
|
||||
}
|
||||
|
||||
// ─── Project Shares ──────────────────────────────────────
|
||||
@@ -456,10 +458,11 @@ export async function createProjectShare(token: string, projectId: string, data:
|
||||
}
|
||||
|
||||
export async function deleteProjectShare(token: string, shareId: string): Promise<void> {
|
||||
await fetch(`${API_BASE}/api/shares/${shareId}`, {
|
||||
const res = await fetch(`${API_BASE}/api/shares/${shareId}`, {
|
||||
method: 'DELETE',
|
||||
headers: authHeaders(token),
|
||||
});
|
||||
if (!res.ok) throw new Error('Failed to delete share');
|
||||
}
|
||||
|
||||
export { API_BASE };
|
||||
|
||||
Reference in New Issue
Block a user