diff --git a/api_documentation.md b/api_documentation.md new file mode 100644 index 0000000..f3717a5 --- /dev/null +++ b/api_documentation.md @@ -0,0 +1,98 @@ +# SecureLens API Documentation (Frontend Integration Guide) + +This document is designed to act as the primary blueprint for the `securelens-frontend` application. It details exactly how the frontend should communicate with the backend. + +**Base URL**: `http://localhost:8000` + +--- + +## 1. Authentication +SecureLens uses JWT Bearer tokens for UI authentication and API Keys for programmatic CI/CD usage. The frontend will rely exclusively on JWTs. + +### `POST /auth/register` +- **Payload**: `{"email": "user@example.com", "username": "user", "password": "securepassword"}` +- **Response**: `{"id": "uuid", "email": "user@example.com", "username": "user"}` + +### `POST /auth/login` +- **Content-Type**: `application/x-www-form-urlencoded` +- **Payload**: `username=user@example.com&password=securepassword` +- **Response**: `{"access_token": "ey...", "token_type": "bearer"}` +- **Action**: Store `access_token` in `localStorage` or secure cookie. Attach it as `Authorization: Bearer ` to all subsequent requests. + +--- + +## 2. Dashboard Analytics +Used for populating the home page charts and historical views. + +### `GET /scans/trends` +- **Auth Required**: Yes +- **Response**: +```json +{ + "total_scans": 12, + "average_score": 85, + "history": [ + {"url": "https://example.com", "score": 90, "date": "2023-10-27T..."}, + {"url": "https://staging.com", "score": 45, "date": "2023-10-26T..."} + ] +} +``` + +--- + +## 3. The Scanning Engine +The core functionality of the product. + +### `POST /scans/scan` +- **Auth Required**: Optional (If authenticated, saves to DB. If anonymous, returns ephemeral result). +- **Payload**: `{"url": "https://example.com"}` +- **Response**: +```json +{ + "id": "abc-123", + "url": "https://example.com", + "security_score": 85, + "layers": { + "Network": "Safe", + "Headers": "Warning" + }, + "issues": [ + { + "issue": "Missing HTTPOnly on Session", + "severity": "Critical", + "layer": "Cookies", + "fix": "Set HttpOnly flag to true", + "contextual_severity": "High", + "explanation": "Because you are using React, XSS could lead to cookie theft...", + "remediation_snippet": "res.cookie('token', token, { httpOnly: true })" + } + ], + "created_at": "2023-10-27T..." +} +``` + +--- + +## 4. AI Interfacing & Diagnostics +Views that trigger LLM behavior based on previous scans. + +### `POST /scans/{scan_id}/chat` +- **Payload**: `{"message": "How do I fix the missing SPF record in AWS Route53?"}` +- **Response**: `{"reply": "To fix this in AWS..."}` + +### `GET /scans/{scan_id}/threat-narrative` +- **Response**: `{"narrative": "An attacker could chain your missing CSP header with your exposed Git directory to..."}` + +### `GET /scans/{old_id}/diff/{new_id}` +- **Response**: Returns lists of `resolved_issues`, `new_issues`, `persisting_issues`, and the integer `score_change`. + +--- + +## 5. Webhooks & Exports +Settings and CI/CD generation views. + +- **`GET /scans/{scan_id}/export/pdf`**: Triggers a browser file download of the PDF report. +- **`GET /scans/{scan_id}/export/csv`**: Triggers a CSV download. +- **`POST /webhooks`**: `{"target_url": "https://my-discord.com/hook"}` +- **`GET /webhooks`**: Returns a list of active webhooks for the user. +- **`DELETE /webhooks/{webhook_id}`**: Revokes a webhook. diff --git a/app/utils/auth.py b/app/utils/auth.py index 6026d31..2531246 100644 --- a/app/utils/auth.py +++ b/app/utils/auth.py @@ -1,19 +1,25 @@ from datetime import datetime, timedelta, timezone +import bcrypt from jose import JWTError, jwt -from passlib.context import CryptContext from app.config import settings -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") - def hash_password(password: str) -> str: - return pwd_context.hash(password) + pwd_bytes = password.encode("utf-8") + salt = bcrypt.gensalt() + return bcrypt.hashpw(pwd_bytes, salt).decode("utf-8") def verify_password(plain_password: str, hashed_password: str) -> bool: - return pwd_context.verify(plain_password, hashed_password) + try: + return bcrypt.checkpw( + plain_password.encode("utf-8"), + hashed_password.encode("utf-8") + ) + except ValueError: + return False def create_access_token(user_id: str) -> str: diff --git a/render.yaml b/render.yaml new file mode 100644 index 0000000..1bf1791 --- /dev/null +++ b/render.yaml @@ -0,0 +1,22 @@ +services: + - type: web + name: securelens-api + env: python + buildCommand: "pip install -r requirements.txt" + startCommand: "uvicorn main:app --host 0.0.0.0 --port $PORT" + envVars: + - key: DATABASE_URL + fromDatabase: + name: securelens-db + property: connectionString + - key: CORS_ORIGINS + value: "*" + - key: JWT_SECRET + generateValue: true + - key: OPENAI_API_KEY + sync: false + +databases: + - name: securelens-db + databaseName: securelens + user: securelens diff --git a/requirements.txt b/requirements.txt index afa5f6d..f59b38b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ sqlalchemy[asyncio] aiosqlite asyncpg python-jose[cryptography] -passlib[bcrypt] +bcrypt pydantic[email] pytest pytest-asyncio