added path security, documented api endpoints
This commit is contained in:
parent
54df891e94
commit
8d78c278ee
|
|
@ -783,7 +783,8 @@ async def get_notes_by_tag_endpoint(tag_name: str):
|
||||||
# --- Template Endpoints ---
|
# --- Template Endpoints ---
|
||||||
|
|
||||||
@api_router.get("/templates")
|
@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.
|
List all available templates from _templates folder.
|
||||||
|
|
||||||
|
|
@ -798,7 +799,8 @@ async def list_templates():
|
||||||
|
|
||||||
|
|
||||||
@api_router.get("/templates/{template_name}")
|
@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.
|
Get content of a specific template.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -668,9 +668,19 @@ def get_templates(notes_dir: str) -> List[Dict]:
|
||||||
if not templates_path.exists():
|
if not templates_path.exists():
|
||||||
return templates
|
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:
|
try:
|
||||||
for template_file in templates_path.glob("*.md"):
|
for template_file in templates_path.glob("*.md"):
|
||||||
try:
|
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()
|
stat = template_file.stat()
|
||||||
templates.append({
|
templates.append({
|
||||||
"name": template_file.stem,
|
"name": template_file.stem,
|
||||||
|
|
|
||||||
|
|
@ -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
|
## 📝 Response Format
|
||||||
|
|
||||||
All endpoints return JSON responses:
|
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!
|
💡 **Tip:** Use the `/api` endpoint to get a live, self-documented list of all available endpoints!
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue