From 8d78c278ee9e58558ad86e4282bb97bcb3504702 Mon Sep 17 00:00:00 2001 From: Gamosoft Date: Wed, 26 Nov 2025 12:01:50 +0100 Subject: [PATCH] added path security, documented api endpoints --- backend/main.py | 6 +- backend/utils.py | 10 +++ documentation/API.md | 150 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+), 2 deletions(-) diff --git a/backend/main.py b/backend/main.py index 37869f9..ad60af4 100644 --- a/backend/main.py +++ b/backend/main.py @@ -783,7 +783,8 @@ async def get_notes_by_tag_endpoint(tag_name: str): # --- Template Endpoints --- @api_router.get("/templates") -async def list_templates(): +@limiter.limit("120/minute") +async def list_templates(request: Request): """ List all available templates from _templates folder. @@ -798,7 +799,8 @@ async def list_templates(): @api_router.get("/templates/{template_name}") -async def get_template(template_name: str): +@limiter.limit("120/minute") +async def get_template(request: Request, template_name: str): """ Get content of a specific template. diff --git a/backend/utils.py b/backend/utils.py index cd69ff3..4d97d8b 100644 --- a/backend/utils.py +++ b/backend/utils.py @@ -668,9 +668,19 @@ def get_templates(notes_dir: str) -> List[Dict]: if not templates_path.exists(): return templates + # Security check: ensure _templates folder is within notes directory + if not validate_path_security(notes_dir, templates_path): + print(f"Security: Templates directory is outside notes directory: {templates_path}") + return templates + try: for template_file in templates_path.glob("*.md"): try: + # Security check: ensure each template is within notes directory + if not validate_path_security(notes_dir, template_file): + print(f"Security: Skipping template outside notes directory: {template_file}") + continue + stat = template_file.stat() templates.append({ "name": template_file.stem, diff --git a/documentation/API.md b/documentation/API.md index 96385bd..3590808 100644 --- a/documentation/API.md +++ b/documentation/API.md @@ -295,6 +295,120 @@ Self-documenting endpoint listing all available API routes. --- +## 🏷️ Tags + +### List All Tags +`GET /api/tags` + +Returns all tags found in notes with their usage counts. + +**Response:** +```json +{ + "tags": { + "python": 5, + "tutorial": 3, + "backend": 2 + } +} +``` + +### Get Notes by Tag +`GET /api/tags/{tag_name}` + +Returns all notes that have a specific tag. + +**Response:** +```json +{ + "tag": "python", + "notes": [ + { + "path": "tutorials/python-basics.md", + "name": "python-basics", + "folder": "tutorials", + "tags": ["python", "tutorial"] + } + ] +} +``` + +--- + +## 📄 Templates + +### List Templates +`GET /api/templates` + +Returns all available note templates from the `_templates` folder. + +**Response:** +```json +{ + "templates": [ + { + "name": "meeting-notes", + "path": "_templates/meeting-notes.md", + "modified": "2025-11-26T10:30:00" + }, + { + "name": "daily-journal", + "path": "_templates/daily-journal.md", + "modified": "2025-11-26T10:25:00" + } + ] +} +``` + +### Get Template Content +`GET /api/templates/{template_name}` + +Returns the content of a specific template. + +**Parameters:** +- `template_name` - Template name (without .md extension) + +**Response:** +```json +{ + "name": "meeting-notes", + "content": "# Meeting Notes\n\nDate: {{date}}\n..." +} +``` + +### Create Note from Template +`POST /api/templates/create-note` + +Creates a new note from a template with placeholder replacement. + +**Request Body:** +```json +{ + "templateName": "meeting-notes", + "notePath": "meetings/weekly-sync.md" +} +``` + +**Placeholders:** +- `{{date}}` - Current date (YYYY-MM-DD) +- `{{time}}` - Current time (HH:MM:SS) +- `{{datetime}}` - Current datetime +- `{{timestamp}}` - Unix timestamp +- `{{title}}` - Note name without extension +- `{{folder}}` - Parent folder name + +**Response:** +```json +{ + "success": true, + "path": "meetings/weekly-sync.md", + "message": "Note created from template successfully", + "content": "# Meeting Notes\n\nDate: 2025-11-26\n..." +} +``` + +--- + ## 📝 Response Format All endpoints return JSON responses: @@ -315,5 +429,41 @@ All endpoints return JSON responses: ``` --- +--- + +## 🔒 Security & Rate Limiting + +### Authentication +When authentication is enabled (via `AUTHENTICATION_ENABLED` environment variable or `config.yaml`), all API endpoints require a valid session cookie obtained through the `/login` endpoint. + +### Rate Limiting +When `DEMO_MODE` is enabled, the following rate limits are enforced: + +**Read Operations:** +- `GET /api/notes` - 120/minute +- `GET /api/templates` - 120/minute +- `GET /api/templates/{template_name}` - 120/minute +- `GET /api/tags` - 120/minute +- `GET /api/tags/{tag}` - 120/minute + +**Write Operations:** +- `POST /api/notes` - 60/minute +- `DELETE /api/notes/*` - 60/minute +- `POST /api/folders` - 60/minute +- `DELETE /api/folders/*` - 60/minute +- `POST /api/images/upload` - 30/minute +- `DELETE /api/images/*` - 60/minute +- `POST /api/templates/create-note` - 60/minute +- `POST /api/plugins/*/toggle` - 60/minute + +### Path Security +All file operations validate that paths are within the configured `notes_dir` to prevent directory traversal attacks. This includes: +- Note operations +- Folder operations +- Image operations +- Template operations + +--- + 💡 **Tip:** Use the `/api` endpoint to get a live, self-documented list of all available endpoints!