Skip to content

Commit cf8f70d

Browse files
committed
fix auth bypass on picker endpoint, async safety, and picker error handling
- Add check_permission to drive-picker-token endpoint (IDOR fix) - Use get_composio_service singleton + asyncio.to_thread to avoid blocking the event loop - Sanitize error detail in 500 response to prevent internal info leakage - Dispose picker on unmount to prevent orphaned overlay - Surface error state on Google Picker Action.ERROR instead of silently closing
1 parent 3bda6c1 commit cf8f70d

File tree

2 files changed

+33
-12
lines changed

2 files changed

+33
-12
lines changed

surfsense_backend/app/routes/search_source_connectors_routes.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@
5252
SearchSourceConnectorRead,
5353
SearchSourceConnectorUpdate,
5454
)
55-
from app.services.composio_service import ComposioService
55+
import asyncio
56+
57+
from app.services.composio_service import ComposioService, get_composio_service
5658
from app.services.notification_service import NotificationService
5759
from app.tasks.connector_indexers import (
5860
index_airtable_records,
@@ -3080,6 +3082,14 @@ async def get_drive_picker_token(
30803082
if not connector:
30813083
raise HTTPException(status_code=404, detail="Connector not found")
30823084

3085+
await check_permission(
3086+
session,
3087+
user,
3088+
connector.search_space_id,
3089+
Permission.CONNECTORS_READ.value,
3090+
"You don't have permission to access this connector",
3091+
)
3092+
30833093
if connector.connector_type not in DRIVE_CONNECTOR_TYPES:
30843094
raise HTTPException(
30853095
status_code=400,
@@ -3113,8 +3123,8 @@ async def get_drive_picker_token(
31133123
status_code=400,
31143124
detail="Composio connected account not found. Please reconnect.",
31153125
)
3116-
service = ComposioService()
3117-
access_token = service.get_access_token(composio_account_id)
3126+
service = get_composio_service()
3127+
access_token = await asyncio.to_thread(service.get_access_token, composio_account_id)
31183128
return {
31193129
"access_token": access_token,
31203130
"client_id": config.GOOGLE_OAUTH_CLIENT_ID,
@@ -3127,5 +3137,5 @@ async def get_drive_picker_token(
31273137
logger.error(f"Failed to get Drive picker token: {e!s}", exc_info=True)
31283138
raise HTTPException(
31293139
status_code=500,
3130-
detail=f"Failed to retrieve access token: {e!s}",
3140+
detail="Failed to retrieve access token. Check server logs for details.",
31313141
) from e

surfsense_web/hooks/use-google-picker.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,14 @@ export function useGooglePicker({ connectorId, onPicked }: UseGooglePickerOption
8787
}
8888
};
8989
window.addEventListener("keydown", onEscape);
90-
return () => window.removeEventListener("keydown", onEscape);
90+
return () => {
91+
window.removeEventListener("keydown", onEscape);
92+
if (pickerRef.current) {
93+
pickerRef.current.dispose();
94+
pickerRef.current = null;
95+
}
96+
openingRef.current = false;
97+
};
9198
}, [closePicker]);
9299

93100
const openPicker = useCallback(async () => {
@@ -147,13 +154,17 @@ export function useGooglePicker({ connectorId, onPicked }: UseGooglePickerOption
147154
}
148155
}
149156

150-
if (
151-
action === google.picker.Action.PICKED ||
152-
action === google.picker.Action.CANCEL ||
153-
action === google.picker.Action.ERROR
154-
) {
155-
closePicker();
156-
}
157+
if (action === google.picker.Action.ERROR) {
158+
setError("Google Drive encountered an error. Please try again.");
159+
}
160+
161+
if (
162+
action === google.picker.Action.PICKED ||
163+
action === google.picker.Action.CANCEL ||
164+
action === google.picker.Action.ERROR
165+
) {
166+
closePicker();
167+
}
157168
})
158169
.build();
159170

0 commit comments

Comments
 (0)