fix: remove basic auth from ui and bump version to 3.0.2
Deploy contracts-flask / validate (push) Canceled after 0s
Deploy contracts-flask / validate (push) Canceled after 0s
This commit is contained in:
+3
-22
@@ -1,7 +1,7 @@
|
|||||||
"""contracts-flask v2.0 — полный перенос с ВМ на Flask.
|
"""contracts-flask v2.0 — полный перенос с ВМ на Flask.
|
||||||
Больше никаких прокси на contracts.kube5s.ru — всё локально.
|
Больше никаких прокси на contracts.kube5s.ru — всё локально.
|
||||||
"""
|
"""
|
||||||
import sys, os, hmac
|
import sys, os
|
||||||
# site/ в sys.path — импортируем модули напрямую, без префиксов
|
# site/ в sys.path — импортируем модули напрямую, без префиксов
|
||||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||||
# корень репо — для переиспользуемого модуля upload/ (как в drhider)
|
# корень репо — для переиспользуемого модуля upload/ (как в drhider)
|
||||||
@@ -9,8 +9,8 @@ _REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|||||||
if _REPO_ROOT not in sys.path:
|
if _REPO_ROOT not in sys.path:
|
||||||
sys.path.insert(0, _REPO_ROOT)
|
sys.path.insert(0, _REPO_ROOT)
|
||||||
|
|
||||||
from flask import Flask, jsonify, request
|
from flask import Flask
|
||||||
from config import VERSION, MAX_CONTENT_LENGTH, API_KEY
|
from config import VERSION, MAX_CONTENT_LENGTH
|
||||||
from routes import register_routes
|
from routes import register_routes
|
||||||
|
|
||||||
|
|
||||||
@@ -18,29 +18,10 @@ def create_app():
|
|||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.config["VERSION"] = VERSION
|
app.config["VERSION"] = VERSION
|
||||||
app.config["MAX_CONTENT_LENGTH"] = MAX_CONTENT_LENGTH
|
app.config["MAX_CONTENT_LENGTH"] = MAX_CONTENT_LENGTH
|
||||||
app.config["API_KEY"] = API_KEY
|
|
||||||
|
|
||||||
_init_db()
|
_init_db()
|
||||||
register_routes(app)
|
register_routes(app)
|
||||||
|
|
||||||
@app.before_request
|
|
||||||
def authorize_request():
|
|
||||||
if request.endpoint == "health.health":
|
|
||||||
return None
|
|
||||||
key = app.config.get("API_KEY", "")
|
|
||||||
if not key:
|
|
||||||
return jsonify(ok=False, error="application API_KEY is not configured"), 503
|
|
||||||
if "X-API-Key" in request.headers:
|
|
||||||
supplied = request.headers.get("X-API-Key", "")
|
|
||||||
else:
|
|
||||||
authorization = request.authorization
|
|
||||||
supplied = authorization.password if authorization and authorization.type.lower() == "basic" else ""
|
|
||||||
if not hmac.compare_digest((supplied or "").encode("utf-8"), key.encode("utf-8")):
|
|
||||||
return jsonify(ok=False, error="unauthorized"), 401, {
|
|
||||||
"WWW-Authenticate": 'Basic realm="Contracts", charset="UTF-8"',
|
|
||||||
}
|
|
||||||
return None
|
|
||||||
|
|
||||||
@app.after_request
|
@app.after_request
|
||||||
def no_cache(response):
|
def no_cache(response):
|
||||||
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
|
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
"""Конфигурация приложения — все настройки в одном месте."""
|
"""Конфигурация приложения — все настройки в одном месте."""
|
||||||
import os
|
import os
|
||||||
|
|
||||||
VERSION = "3.0.1"
|
VERSION = "3.0.2"
|
||||||
|
|
||||||
|
|
||||||
def _load_env():
|
def _load_env():
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"""Pipeline blueprint — SSE-сравнение + classify."""
|
"""Pipeline blueprint — SSE-сравнение + classify."""
|
||||||
import hashlib, json, re, os, threading, time
|
import hashlib, hmac, json, re, os, threading, time
|
||||||
from flask import Blueprint, request, jsonify, Response, stream_with_context
|
from flask import Blueprint, request, jsonify, Response, stream_with_context
|
||||||
|
from config import API_KEY
|
||||||
from services.process import run_pipeline
|
from services.process import run_pipeline
|
||||||
from services import extractor as stateless_extractor
|
from services import extractor as stateless_extractor
|
||||||
from services.engine import analyze_batch
|
from services.engine import analyze_batch
|
||||||
@@ -143,6 +144,11 @@ def engine_analyze_route():
|
|||||||
supplies parsed elements only; extraction passports and dossier decisions
|
supplies parsed elements only; extraction passports and dossier decisions
|
||||||
are always produced by the in-process Engine and persisted by its adapters.
|
are always produced by the in-process Engine and persisted by its adapters.
|
||||||
"""
|
"""
|
||||||
|
if not API_KEY:
|
||||||
|
return jsonify(ok=False, error="engine API is not configured"), 503
|
||||||
|
supplied_key = request.headers.get("X-API-Key", "")
|
||||||
|
if not hmac.compare_digest(supplied_key.encode("utf-8"), API_KEY.encode("utf-8")):
|
||||||
|
return jsonify(ok=False, error="unauthorized"), 401
|
||||||
if _engine_rate_limited():
|
if _engine_rate_limited():
|
||||||
return jsonify(ok=False, error="rate limit exceeded"), 429, {"Retry-After": "60"}
|
return jsonify(ok=False, error="rate limit exceeded"), 429, {"Retry-After": "60"}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user