-
Notifications
You must be signed in to change notification settings - Fork 4.2k
fix: upgrade credential encryption key derivation to PBKDF2 #1020
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
5869b91
04cfbea
5ae0c01
54f0080
d17c560
19ac94d
2382bbd
3b9cb26
f329843
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,7 @@ | |
| from loguru import logger | ||
|
|
||
| from api.models import ContextRequest, ContextResponse | ||
| from open_notebook.domain.notebook import Note, Notebook, Source | ||
| from open_notebook.domain.notebook import Note, Notebook, Source, SourceInsight | ||
| from open_notebook.exceptions import InvalidInputError | ||
| from open_notebook.utils import token_count | ||
|
|
||
|
|
@@ -77,9 +77,21 @@ async def get_notebook_context(notebook_id: str, context_request: ContextRequest | |
| else: | ||
| # Default behavior - include all sources and notes with short context | ||
| sources = await notebook.get_sources() | ||
| try: | ||
| insights_by_source = await SourceInsight.get_for_sources( | ||
| [source.id for source in sources if source.id] | ||
| ) | ||
| except Exception as e: | ||
| # Match the per-source fallback below: a hiccup fetching | ||
| # insights shouldn't fail the whole context request. | ||
| logger.warning(f"Error batch-fetching source insights: {str(e)}") | ||
| insights_by_source = {} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: When the batch insight fetch fails, all source insights are silently dropped from the context response instead of falling back to per-source queries. The Prompt for AI agents |
||
| for source in sources: | ||
| try: | ||
| source_context = await source.get_context(context_size="short") | ||
| source_context = await source.get_context( | ||
| context_size="short", | ||
| insights=insights_by_source.get(source.id or "", []), | ||
| ) | ||
| context_data["source"].append(source_context) | ||
| total_content += str(source_context) | ||
| except Exception as e: | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -17,6 +17,7 @@ | |||||
| from surreal_commands import execute_command_sync, submit_command | ||||||
|
|
||||||
| from api.command_service import CommandService | ||||||
| from api.credentials_service import validate_url | ||||||
| from api.models import ( | ||||||
| AssetModel, | ||||||
| CreateSourceInsightRequest, | ||||||
|
|
@@ -96,18 +97,12 @@ def generate_unique_filename(original_filename: str, upload_folder: str) -> str: | |||||
| counter += 1 | ||||||
|
|
||||||
|
|
||||||
| async def save_uploaded_file(upload_file: UploadFile) -> str: | ||||||
| """Save uploaded file to uploads folder and return file path.""" | ||||||
| if not upload_file.filename: | ||||||
| raise ValueError("No filename provided") | ||||||
|
|
||||||
| # Generate unique filename | ||||||
| file_path = generate_unique_filename(upload_file.filename, UPLOADS_FOLDER) | ||||||
|
|
||||||
| def _write_uploaded_file(filename: str, content: bytes) -> str: | ||||||
| """Sync filesystem work for save_uploaded_file() - run via asyncio.to_thread | ||||||
| so a large upload doesn't block the event loop for other requests.""" | ||||||
| file_path = generate_unique_filename(filename, UPLOADS_FOLDER) | ||||||
| try: | ||||||
| # Save file | ||||||
| with open(file_path, "wb") as f: | ||||||
| content = await upload_file.read() | ||||||
| f.write(content) | ||||||
|
|
||||||
| logger.info(f"Saved uploaded file to: {file_path}") | ||||||
|
|
@@ -120,6 +115,15 @@ async def save_uploaded_file(upload_file: UploadFile) -> str: | |||||
| raise | ||||||
|
|
||||||
|
|
||||||
| async def save_uploaded_file(upload_file: UploadFile) -> str: | ||||||
| """Save uploaded file to uploads folder and return file path.""" | ||||||
| if not upload_file.filename: | ||||||
| raise ValueError("No filename provided") | ||||||
|
|
||||||
| content = await upload_file.read() | ||||||
| return await asyncio.to_thread(_write_uploaded_file, upload_file.filename, content) | ||||||
|
|
||||||
|
|
||||||
| def parse_source_form_data( | ||||||
| type: str = Form(...), | ||||||
| notebook_id: Optional[str] = Form(None), | ||||||
|
|
@@ -360,6 +364,12 @@ async def create_source( | |||||
| raise HTTPException( | ||||||
| status_code=400, detail="URL is required for link type" | ||||||
| ) | ||||||
| # Block SSRF to internal/metadata addresses before the server ever | ||||||
| # fetches this URL (same guard used for provider-credential URLs). | ||||||
| try: | ||||||
| validate_url(source_data.url, "source") | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: Link source ingestion still permits SSRF to loopback/private network targets because Prompt for AI agents
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Creating a link source can stall other API requests while DNS resolution runs because Prompt for AI agents
Suggested change
|
||||||
| except ValueError as e: | ||||||
| raise HTTPException(status_code=400, detail=str(e)) | ||||||
| content_state["url"] = source_data.url | ||||||
| elif source_data.type == "upload": | ||||||
| # Use uploaded file path or provided file_path (backward compatibility) | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: OpenAI custom model discovery still has the DNS-rebinding gap this change closes for other user-configured URLs. The
openaipath later uses credentialbase_urlfordiscovery_urlwithout a request-timevalidate_url(), so revalidating that path beforehttpx.getwould keep Discover Models consistent withollama,openai_compatible, andazure.Prompt for AI agents