mirror of
https://github.com/LearningCircuit/local-deep-research.git
synced 2026-06-15 19:46:56 +03:00
* feat: extend resource leak hook to detect database session leaks The pre-commit hook now detects unsafe usage of get_auth_db_session() and suggests using the auth_db_session() context manager instead. This prevents database session leaks when exceptions occur. Changes: - Add FUNCTIONS_REQUIRING_CONTEXT to detect function calls that return resources needing cleanup - Fix nested try/finally detection for close() calls - Update user_exists() in encrypted_db.py to use context manager - Update example files to use auth_db_session() context manager * fix: prevent session use after close and add search engine cleanup - Move config dict creation inside with block in api_routes.py to prevent using SettingsManager after database session is closed (was causing errors) - Remove redundant session.close() call that was after context manager exit - Add close() method and context manager support to BaseSearchEngine so search engines with HTTP sessions can be properly cleaned up
265 lines
9.0 KiB
Python
265 lines
9.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Simple Working HTTP API Example for Local Deep Research v1.0+
|
|
|
|
This is a clean, working example that demonstrates the correct way to use the LDR API.
|
|
It creates a user automatically and handles authentication properly.
|
|
|
|
Requirements:
|
|
- LDR v1.0+ server running: python -m local_deep_research.web.app
|
|
- Beautiful Soup: pip install beautifulsoup4
|
|
|
|
================================================================================
|
|
IMPORTANT - LOCALHOST ONLY
|
|
================================================================================
|
|
This example ONLY works when connecting via localhost:
|
|
✅ http://localhost:5000
|
|
✅ http://127.0.0.1:5000
|
|
|
|
It will NOT work when connecting via:
|
|
❌ http://192.168.x.x:5000 (local network IP)
|
|
❌ http://your-server.com:5000 (remote server)
|
|
❌ http://0.0.0.0:5000 (even from the same machine)
|
|
|
|
WHY: For security, session cookies require HTTPS for non-localhost connections.
|
|
This prevents session hijacking on untrusted networks.
|
|
|
|
SOLUTIONS for non-localhost access:
|
|
1. Use HTTPS with a reverse proxy (recommended for production)
|
|
2. SSH tunnel: ssh -L 5000:localhost:5000 user@server, then use localhost:5000
|
|
3. Set TESTING=1 when starting server (INSECURE - development only!)
|
|
Example: TESTING=1 python -m local_deep_research.web.app
|
|
|
|
WARNING: TESTING=1 disables secure cookie protection. Session cookies can be
|
|
intercepted by network attackers. Never use in production or on public networks.
|
|
================================================================================
|
|
"""
|
|
|
|
import requests
|
|
from bs4 import BeautifulSoup
|
|
import sys
|
|
import time
|
|
from pathlib import Path
|
|
|
|
# Add the src directory to Python path for programmatic user creation
|
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent / "src"))
|
|
|
|
from local_deep_research.database.encrypted_db import DatabaseManager
|
|
from local_deep_research.database.models import User
|
|
from local_deep_research.database.auth_db import auth_db_session
|
|
|
|
|
|
def create_test_user():
|
|
"""Create a test user programmatically - works out of the box!"""
|
|
username = f"testuser_{int(time.time())}"
|
|
password = "testpassword123"
|
|
|
|
print(f"Creating test user: {username}")
|
|
|
|
try:
|
|
# Create user in auth database
|
|
with auth_db_session() as session:
|
|
new_user = User(username=username)
|
|
session.add(new_user)
|
|
session.commit()
|
|
|
|
# Create encrypted database for user
|
|
db_manager = DatabaseManager()
|
|
db_manager.create_user_database(username, password)
|
|
|
|
print(f"✅ User created successfully: {username}")
|
|
return username, password
|
|
|
|
except Exception as e:
|
|
print(f"❌ Failed to create user: {e}")
|
|
return None, None
|
|
|
|
|
|
def test_api_with_user(username, password):
|
|
"""Test the API with the created user."""
|
|
print(f"\n=== Testing API with user: {username} ===")
|
|
|
|
base_url = "http://localhost:5000"
|
|
session = requests.Session()
|
|
|
|
# 1. Test login
|
|
print("1. Testing login...")
|
|
try:
|
|
login_page = session.get(f"{base_url}/auth/login")
|
|
if login_page.status_code != 200:
|
|
print(f" ❌ Failed to get login page: {login_page.status_code}")
|
|
return False
|
|
|
|
soup = BeautifulSoup(login_page.text, "html.parser")
|
|
csrf_input = soup.find("input", {"name": "csrf_token"})
|
|
login_csrf = csrf_input.get("value")
|
|
|
|
if not login_csrf:
|
|
print(" ❌ No CSRF token found")
|
|
return False
|
|
|
|
login_response = session.post(
|
|
f"{base_url}/auth/login",
|
|
data={
|
|
"username": username,
|
|
"password": password,
|
|
"csrf_token": login_csrf,
|
|
},
|
|
allow_redirects=False,
|
|
)
|
|
|
|
print(f" Login status: {login_response.status_code}")
|
|
|
|
if login_response.status_code not in [200, 302]:
|
|
print(" ❌ Login failed")
|
|
return False
|
|
|
|
print(" ✅ Login successful")
|
|
|
|
except Exception as e:
|
|
print(f" ❌ Login error: {e}")
|
|
return False
|
|
|
|
# 2. Get CSRF token for API
|
|
print("\n2. Getting API CSRF token...")
|
|
try:
|
|
csrf_response = session.get(f"{base_url}/auth/csrf-token")
|
|
if csrf_response.status_code != 200:
|
|
print(
|
|
f" ❌ Failed to get CSRF token: {csrf_response.status_code}"
|
|
)
|
|
return False
|
|
|
|
csrf_data = csrf_response.json()
|
|
csrf_token = csrf_data.get("csrf_token")
|
|
|
|
if not csrf_token:
|
|
print(" ❌ No CSRF token in response")
|
|
return False
|
|
|
|
print(f" ✅ API CSRF token: {csrf_token[:20]}...")
|
|
|
|
except Exception as e:
|
|
print(f" ❌ CSRF token error: {e}")
|
|
return False
|
|
|
|
# 3. Test research API
|
|
print("\n3. Testing research API...")
|
|
|
|
research_request = {
|
|
"query": "What is machine learning?",
|
|
"model": "gpt-4o-mini",
|
|
"search_engines": ["searxng"],
|
|
}
|
|
|
|
headers = {"X-CSRF-Token": csrf_token, "Content-Type": "application/json"}
|
|
|
|
# Test the correct endpoint
|
|
print("\n 3.1 Testing /api/start_research...")
|
|
try:
|
|
url = f"{base_url}/api/start_research"
|
|
response = session.post(url, json=research_request, headers=headers)
|
|
|
|
print(f" Status: {response.status_code}")
|
|
print(f" Response: {response.text[:300]}")
|
|
|
|
if response.status_code == 200:
|
|
try:
|
|
data = response.json()
|
|
if data.get("status") == "success":
|
|
print(" ✅ Research started successfully!")
|
|
research_id = data.get("research_id")
|
|
if research_id:
|
|
print(f" Research ID: {research_id}")
|
|
print("\n🎉 SUCCESS! API is working correctly.")
|
|
print(
|
|
f"📊 View results at: {base_url}/results/{research_id}"
|
|
)
|
|
return True
|
|
elif data.get("status") == "queued":
|
|
print(" ✅ Research queued successfully!")
|
|
return True
|
|
else:
|
|
print(
|
|
f" ⚠️ Research returned: {data.get('status', 'unknown')}"
|
|
)
|
|
except Exception:
|
|
print(" ⚠️ Response is not valid JSON")
|
|
elif response.status_code == 401:
|
|
print(" ❌ Authentication failed")
|
|
elif response.status_code == 403:
|
|
print(" ❌ Forbidden - CSRF token issue")
|
|
elif response.status_code == 404:
|
|
print(" ❌ Endpoint not found")
|
|
elif response.status_code == 500:
|
|
print(" ❌ Server error")
|
|
print(" Check server logs: tail -f /tmp/ldr_server.log")
|
|
else:
|
|
print(" ⚠️ Unexpected status code")
|
|
|
|
except Exception as e:
|
|
print(f" ❌ Error testing endpoint: {e}")
|
|
|
|
return False
|
|
|
|
|
|
def main():
|
|
"""Main function that works completely out of the box!"""
|
|
print("=== Simple LDR API Working Example ===")
|
|
print(
|
|
"🎯 This example works completely out of the box - no manual setup required!\n"
|
|
)
|
|
|
|
# Check if server is running
|
|
try:
|
|
response = requests.get("http://localhost:5000/", timeout=5)
|
|
if response.status_code != 200:
|
|
print("❌ Server is not responding correctly")
|
|
print("\nPlease start the server:")
|
|
print(" python -m local_deep_research.web.app")
|
|
sys.exit(1)
|
|
print("✅ Server is running")
|
|
except Exception:
|
|
print(
|
|
"❌ Cannot connect to server. Please make sure it's running on http://localhost:5000"
|
|
)
|
|
print("\nStart the server with:")
|
|
print(" python -m local_deep_research.web.app")
|
|
sys.exit(1)
|
|
|
|
# Create test user automatically
|
|
username, password = create_test_user()
|
|
if not username:
|
|
print("❌ Failed to create test user")
|
|
sys.exit(1)
|
|
|
|
# Test API
|
|
success = test_api_with_user(username, password)
|
|
|
|
if success:
|
|
print("\n✅ API test completed successfully")
|
|
print(f"\n🔑 Created user: {username}")
|
|
print("📝 You can now use this user for manual testing:")
|
|
print(f" Username: {username}")
|
|
print(f" Password: {password}")
|
|
print(" Login URL: http://localhost:5000/auth/login")
|
|
print("\nNext steps:")
|
|
print("- Try different research queries")
|
|
print("- Explore other API endpoints")
|
|
print("- Check out the web interface at http://localhost:5000")
|
|
print("- Use the credentials above to log in manually")
|
|
sys.exit(0)
|
|
else:
|
|
print("\n❌ API test failed")
|
|
print("\nTroubleshooting:")
|
|
print(
|
|
"- Make sure the server is running: python -m local_deep_research.web.app"
|
|
)
|
|
print("- Check server logs for errors: tail -f /tmp/ldr_server.log")
|
|
print("- Ensure all dependencies are installed")
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|