Fix distillation bugs: imports, auth security, and run configuration
- Fix bare imports in core/ modules to use fully-qualified paths (core.users, core.postgres) - Fix scheduler/daemon.py importing os before use - Fix verifyLoginToken returning truthy 401 on failure (security: invalid tokens were passing auth checks) - Fix api/routes/example.py passing literal True as userUUID instead of decoded JWT sub - Switch all services to python -m invocation so /app is always on sys.path - Remove orphaned sys.path.insert hacks from bot.py, commands/example.py, routes/example.py - Change API port mapping from 5000 to 8080 - Add config/.env and root .env for docker-compose variable substitution Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,4 +7,4 @@ RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
CMD ["python", "api/main.py"]
|
||||
CMD ["python", "-m", "api.main"]
|
||||
|
||||
@@ -7,16 +7,22 @@ This module demonstrates:
|
||||
3. Making database calls via postgres module
|
||||
"""
|
||||
|
||||
import flask
|
||||
import sys
|
||||
import os
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
import flask
|
||||
import jwt
|
||||
import core.auth as auth
|
||||
import core.postgres as postgres
|
||||
|
||||
|
||||
def _get_user_uuid(token):
|
||||
"""Decode JWT to extract user UUID. Returns None on failure."""
|
||||
try:
|
||||
payload = jwt.decode(token, os.getenv("JWT_SECRET"), algorithms=["HS256"])
|
||||
return payload.get("sub")
|
||||
except (jwt.ExpiredSignatureError, jwt.InvalidTokenError):
|
||||
return None
|
||||
|
||||
|
||||
def register(app):
|
||||
"""Register routes with the Flask app."""
|
||||
|
||||
@@ -27,8 +33,8 @@ def register(app):
|
||||
return flask.jsonify({"error": "missing token"}), 401
|
||||
token = header[7:]
|
||||
|
||||
decoded = auth.verifyLoginToken(token, userUUID=True)
|
||||
if decoded != True:
|
||||
user_uuid = _get_user_uuid(token)
|
||||
if not user_uuid or not auth.verifyLoginToken(token, userUUID=user_uuid):
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
|
||||
items = postgres.select("examples")
|
||||
@@ -41,8 +47,8 @@ def register(app):
|
||||
return flask.jsonify({"error": "missing token"}), 401
|
||||
token = header[7:]
|
||||
|
||||
decoded = auth.verifyLoginToken(token, userUUID=True)
|
||||
if decoded != True:
|
||||
user_uuid = _get_user_uuid(token)
|
||||
if not user_uuid or not auth.verifyLoginToken(token, userUUID=user_uuid):
|
||||
return flask.jsonify({"error": "unauthorized"}), 401
|
||||
|
||||
data = flask.request.get_json()
|
||||
|
||||
@@ -18,8 +18,6 @@ import requests
|
||||
import bcrypt
|
||||
import pickle
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from bot.command_registry import get_handler, list_registered
|
||||
import ai.parser as ai_parser
|
||||
|
||||
|
||||
@@ -7,11 +7,6 @@ This module demonstrates:
|
||||
3. Making API calls
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from bot.command_registry import register_module
|
||||
import ai.parser as ai_parser
|
||||
|
||||
|
||||
11
config/.env
Normal file
11
config/.env
Normal file
@@ -0,0 +1,11 @@
|
||||
DISCORD_BOT_TOKEN=MTQ2NzYwMTc2ODM0NjE2MTE3Mw.G7BKQ-.kivCRj7mOl6aS5VyX4RW9hirqzm7qJ8nJOVMpE
|
||||
API_URL=http://app:5000
|
||||
DB_HOST=db
|
||||
DB_PORT=5432
|
||||
DB_NAME=app
|
||||
DB_USER=app
|
||||
DB_PASS=y8Khu7pJQZq6ywFDIJiqpx4zYmclHGHw
|
||||
JWT_SECRET=bf773b4562221bef4d304ae5752a68931382ea3e98fe38394a098f73e0c776e1
|
||||
OPENROUTER_API_KEY=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
|
||||
OPENROUTER_BASE_URL=https://openrouter.ai/api/v1
|
||||
AI_CONFIG_PATH=/app/ai/ai_config.json
|
||||
10
core/auth.py
10
core/auth.py
@@ -1,5 +1,5 @@
|
||||
import users
|
||||
import postgres
|
||||
import core.users as users
|
||||
import core.postgres as postgres
|
||||
import bcrypt
|
||||
import jwt
|
||||
from jwt.exceptions import ExpiredSignatureError, InvalidTokenError
|
||||
@@ -19,9 +19,9 @@ def verifyLoginToken(login_token, username=False, userUUID=False):
|
||||
if decoded_token.get("sub") == str(userUUID):
|
||||
return True
|
||||
return False
|
||||
except:
|
||||
return 401
|
||||
return 401
|
||||
except (ExpiredSignatureError, InvalidTokenError):
|
||||
return False
|
||||
return False
|
||||
|
||||
|
||||
def getUserpasswordHash(userUUID):
|
||||
|
||||
@@ -4,7 +4,7 @@ notifications.py - Multi-channel notification routing
|
||||
Supported channels: Discord webhook, ntfy
|
||||
"""
|
||||
|
||||
import postgres
|
||||
import core.postgres as postgres
|
||||
import uuid
|
||||
import requests
|
||||
import time
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import uuid
|
||||
import postgres
|
||||
import core.postgres as postgres
|
||||
import bcrypt
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ services:
|
||||
app:
|
||||
build: .
|
||||
ports:
|
||||
- "5000:5000"
|
||||
- "8080:5000"
|
||||
env_file: config/.env
|
||||
depends_on:
|
||||
db:
|
||||
@@ -27,7 +27,7 @@ services:
|
||||
|
||||
scheduler:
|
||||
build: .
|
||||
command: ["python", "scheduler/daemon.py"]
|
||||
command: ["python", "-m", "scheduler.daemon"]
|
||||
env_file: config/.env
|
||||
depends_on:
|
||||
db:
|
||||
@@ -35,7 +35,7 @@ services:
|
||||
|
||||
bot:
|
||||
build: .
|
||||
command: ["python", "bot/bot.py"]
|
||||
command: ["python", "-m", "bot.bot"]
|
||||
env_file: config/.env
|
||||
depends_on:
|
||||
app:
|
||||
|
||||
@@ -4,6 +4,7 @@ daemon.py - Background polling loop for scheduled tasks
|
||||
Override poll_callback() with your domain-specific logic.
|
||||
"""
|
||||
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
|
||||
@@ -32,6 +33,4 @@ def daemon_loop():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import os
|
||||
|
||||
daemon_loop()
|
||||
|
||||
Reference in New Issue
Block a user