chimera-api 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- app/__init__.py +302 -0
- app/blueprints/admin/__init__.py +9 -0
- app/blueprints/admin/routes.py +708 -0
- app/blueprints/attack_sim/__init__.py +9 -0
- app/blueprints/attack_sim/routes.py +577 -0
- app/blueprints/auth/__init__.py +9 -0
- app/blueprints/auth/routes.py +1158 -0
- app/blueprints/banking/__init__.py +9 -0
- app/blueprints/banking/routes.py +880 -0
- app/blueprints/checkout/__init__.py +9 -0
- app/blueprints/checkout/routes.py +124 -0
- app/blueprints/compliance/__init__.py +9 -0
- app/blueprints/compliance/routes.py +218 -0
- app/blueprints/database_vulnerable/__init__.py +15 -0
- app/blueprints/database_vulnerable/routes.py +340 -0
- app/blueprints/diagnostics/__init__.py +9 -0
- app/blueprints/diagnostics/routes.py +70 -0
- app/blueprints/ecommerce/__init__.py +9 -0
- app/blueprints/ecommerce/routes.py +588 -0
- app/blueprints/energy_utilities/__init__.py +9 -0
- app/blueprints/energy_utilities/routes.py +414 -0
- app/blueprints/genai/__init__.py +9 -0
- app/blueprints/genai/routes.py +261 -0
- app/blueprints/government/__init__.py +9 -0
- app/blueprints/government/routes.py +684 -0
- app/blueprints/healthcare/__init__.py +9 -0
- app/blueprints/healthcare/routes.py +956 -0
- app/blueprints/ics_ot/__init__.py +9 -0
- app/blueprints/ics_ot/routes.py +266 -0
- app/blueprints/infrastructure/__init__.py +9 -0
- app/blueprints/infrastructure/routes.py +269 -0
- app/blueprints/insurance/__init__.py +9 -0
- app/blueprints/insurance/routes.py +838 -0
- app/blueprints/integrations/__init__.py +9 -0
- app/blueprints/integrations/routes.py +133 -0
- app/blueprints/loyalty/__init__.py +9 -0
- app/blueprints/loyalty/routes.py +195 -0
- app/blueprints/main/__init__.py +9 -0
- app/blueprints/main/routes.py +41 -0
- app/blueprints/mobile/__init__.py +9 -0
- app/blueprints/mobile/routes.py +146 -0
- app/blueprints/payments/__init__.py +9 -0
- app/blueprints/payments/routes.py +683 -0
- app/blueprints/recorder/__init__.py +9 -0
- app/blueprints/recorder/routes.py +39 -0
- app/blueprints/saas/__init__.py +9 -0
- app/blueprints/saas/routes.py +567 -0
- app/blueprints/security_ops/__init__.py +9 -0
- app/blueprints/security_ops/routes.py +163 -0
- app/blueprints/telecom/__init__.py +9 -0
- app/blueprints/telecom/routes.py +448 -0
- app/blueprints/testing/__init__.py +13 -0
- app/blueprints/testing/routes.py +364 -0
- app/blueprints/throughput/__init__.py +9 -0
- app/blueprints/throughput/routes.py +75 -0
- app/cli.py +40 -0
- app/database.py +313 -0
- app/error_handlers.py +307 -0
- app/middleware/traffic_recorder.py +67 -0
- app/models/__init__.py +200 -0
- app/models/dal.py +391 -0
- app/models/data_stores.py +363 -0
- app/models.py +216 -0
- app/throughput.py +62 -0
- app/utils/__init__.py +155 -0
- app/utils/auth_helpers.py +528 -0
- app/utils/demo_data.py +1045 -0
- app/utils/monitoring.py +510 -0
- app/utils/responses.py +507 -0
- app/utils/templates.py +124 -0
- app/utils/validators.py +544 -0
- app/web_dist/assets/index-Ce9aAr74.js +613 -0
- app/web_dist/assets/index-DoKhh6ts.css +1 -0
- app/web_dist/index.html +13 -0
- chimera_api-0.1.1.dist-info/METADATA +17 -0
- chimera_api-0.1.1.dist-info/RECORD +78 -0
- chimera_api-0.1.1.dist-info/WHEEL +4 -0
- chimera_api-0.1.1.dist-info/entry_points.txt +2 -0
app/__init__.py
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Application factory for the WAF Demo Site.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from flask import Flask, Response, jsonify, request, send_from_directory
|
|
7
|
+
|
|
8
|
+
from app.throughput import (
|
|
9
|
+
bool_env,
|
|
10
|
+
int_env,
|
|
11
|
+
throughput_payload_bytes,
|
|
12
|
+
build_payload_cache
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def create_app(config=None):
|
|
17
|
+
"""
|
|
18
|
+
Application factory pattern for creating Flask app instances.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
config: Optional configuration dictionary
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
Configured Flask application instance
|
|
25
|
+
"""
|
|
26
|
+
app = Flask(__name__, static_folder='../static')
|
|
27
|
+
|
|
28
|
+
# Basic configuration
|
|
29
|
+
app.secret_key = config.get('SECRET_KEY', 'chimera-demo-key-not-for-production') if config else 'chimera-demo-key-not-for-production'
|
|
30
|
+
|
|
31
|
+
# Initialize Swagger (legacy flasgger setup retained for backward compatibility)
|
|
32
|
+
from flasgger import Swagger
|
|
33
|
+
swagger_template = {
|
|
34
|
+
"swagger": "2.0",
|
|
35
|
+
"info": {
|
|
36
|
+
"title": " Demo API",
|
|
37
|
+
"description": "API Documentation for WAF TestBed. <br><br><b>Note:</b> This API contains intentional vulnerabilities for educational and testing purposes.",
|
|
38
|
+
"version": "1.0.0"
|
|
39
|
+
},
|
|
40
|
+
"schemes": [
|
|
41
|
+
"http",
|
|
42
|
+
"https"
|
|
43
|
+
],
|
|
44
|
+
"securityDefinitions": {
|
|
45
|
+
"Bearer": {
|
|
46
|
+
"type": "apiKey",
|
|
47
|
+
"name": "Authorization",
|
|
48
|
+
"in": "header",
|
|
49
|
+
"description": "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\""
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
Swagger(app, template=swagger_template)
|
|
54
|
+
|
|
55
|
+
# Enable debug mode for demo environment to ensure verbose error responses
|
|
56
|
+
demo_mode = os.environ.get('DEMO_MODE', 'true').lower() == 'true'
|
|
57
|
+
if demo_mode:
|
|
58
|
+
app.config['DEBUG'] = True
|
|
59
|
+
app.config['ENV'] = 'development'
|
|
60
|
+
app.config['DEMO_MODE'] = True
|
|
61
|
+
|
|
62
|
+
# Initialize database if USE_DATABASE=true
|
|
63
|
+
use_database = os.environ.get('USE_DATABASE', 'false').lower() == 'true'
|
|
64
|
+
if use_database:
|
|
65
|
+
from app.database import init_database
|
|
66
|
+
db_initialized = init_database(app)
|
|
67
|
+
if db_initialized:
|
|
68
|
+
print("✓ Database mode enabled (SQLite)")
|
|
69
|
+
else:
|
|
70
|
+
print("✗ Database initialization failed")
|
|
71
|
+
else:
|
|
72
|
+
print("✓ In-memory mode (no database)")
|
|
73
|
+
|
|
74
|
+
throughput_mode = bool_env('DEMO_THROUGHPUT_MODE')
|
|
75
|
+
if throughput_mode:
|
|
76
|
+
payload_bytes = throughput_payload_bytes()
|
|
77
|
+
payload_cache = build_payload_cache(payload_bytes)
|
|
78
|
+
payload = payload_cache[payload_bytes]
|
|
79
|
+
payload_size = len(payload)
|
|
80
|
+
max_payload_bytes = int_env('DEMO_THROUGHPUT_MAX_BYTES') or (1024 * 1024)
|
|
81
|
+
throughput_only_fast = bool_env('DEMO_THROUGHPUT_ONLY_FAST')
|
|
82
|
+
match_paths = [p.strip() for p in os.environ.get('DEMO_THROUGHPUT_PATHS', '').split(',') if p.strip()]
|
|
83
|
+
exclude_paths = [p.strip() for p in os.environ.get('DEMO_THROUGHPUT_EXCLUDE_PATHS', '').split(',') if p.strip()]
|
|
84
|
+
|
|
85
|
+
app.config['DEMO_THROUGHPUT_MODE'] = True
|
|
86
|
+
app.config['DEMO_THROUGHPUT_PAYLOAD'] = payload
|
|
87
|
+
app.config['DEMO_THROUGHPUT_PAYLOAD_BYTES'] = payload_size
|
|
88
|
+
app.config['DEMO_THROUGHPUT_PAYLOAD_CACHE'] = payload_cache
|
|
89
|
+
app.config['DEMO_THROUGHPUT_MAX_BYTES'] = max_payload_bytes
|
|
90
|
+
app.config['DEMO_THROUGHPUT_ONLY_FAST'] = throughput_only_fast
|
|
91
|
+
app.config['DEMO_THROUGHPUT_PATHS'] = match_paths
|
|
92
|
+
app.config['DEMO_THROUGHPUT_EXCLUDE_PATHS'] = exclude_paths
|
|
93
|
+
|
|
94
|
+
@app.before_request
|
|
95
|
+
def short_circuit_exports():
|
|
96
|
+
if throughput_only_fast:
|
|
97
|
+
return None
|
|
98
|
+
if request.method not in {'GET', 'POST'}:
|
|
99
|
+
return None
|
|
100
|
+
path = request.path or ''
|
|
101
|
+
if exclude_paths and any(token in path for token in exclude_paths):
|
|
102
|
+
return None
|
|
103
|
+
if match_paths:
|
|
104
|
+
if not any(token in path for token in match_paths):
|
|
105
|
+
return None
|
|
106
|
+
elif 'export' not in path:
|
|
107
|
+
return None
|
|
108
|
+
|
|
109
|
+
response = Response(payload, mimetype='application/json')
|
|
110
|
+
response.headers['X-Demo-Throughput'] = 'true'
|
|
111
|
+
response.headers['X-Demo-Throughput-Bytes'] = str(payload_size)
|
|
112
|
+
return response
|
|
113
|
+
|
|
114
|
+
# Register Security Headers (CSP + CORS)
|
|
115
|
+
@app.after_request
|
|
116
|
+
def add_security_headers(response):
|
|
117
|
+
"""Set Content-Security-Policy and CORS headers for all responses"""
|
|
118
|
+
# CORS Headers - Intentionally permissive for demo
|
|
119
|
+
response.headers['Access-Control-Allow-Origin'] = '*'
|
|
120
|
+
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
|
|
121
|
+
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, X-Requested-With'
|
|
122
|
+
|
|
123
|
+
if request.path in {'/swagger', '/openapi.yaml'}:
|
|
124
|
+
response.headers['Content-Security-Policy'] = (
|
|
125
|
+
"default-src 'self' https://unpkg.com; "
|
|
126
|
+
"style-src 'self' https://unpkg.com 'unsafe-inline'; "
|
|
127
|
+
"script-src 'self' https://unpkg.com 'unsafe-inline'; "
|
|
128
|
+
"img-src 'self' data: https://unpkg.com; "
|
|
129
|
+
"font-src 'self' https://unpkg.com; "
|
|
130
|
+
"connect-src 'self'"
|
|
131
|
+
)
|
|
132
|
+
return response
|
|
133
|
+
|
|
134
|
+
# SPA routes need relaxed CSP for Tailwind/Vite inline styles
|
|
135
|
+
if not request.path.startswith(('/api/', '/apidocs', '/flasgger_static', '/apispec')):
|
|
136
|
+
response.headers['Content-Security-Policy'] = (
|
|
137
|
+
"default-src 'self'; "
|
|
138
|
+
"style-src 'self' 'unsafe-inline'; "
|
|
139
|
+
"script-src 'self'; "
|
|
140
|
+
"img-src 'self' data:; "
|
|
141
|
+
"font-src 'self'; "
|
|
142
|
+
"connect-src 'self'"
|
|
143
|
+
)
|
|
144
|
+
else:
|
|
145
|
+
response.headers['Content-Security-Policy'] = (
|
|
146
|
+
"default-src 'self'; "
|
|
147
|
+
"style-src 'self'; "
|
|
148
|
+
"script-src 'self'; "
|
|
149
|
+
"img-src 'self' data:; "
|
|
150
|
+
"font-src 'self'; "
|
|
151
|
+
"connect-src 'self'"
|
|
152
|
+
)
|
|
153
|
+
return response
|
|
154
|
+
|
|
155
|
+
# Register error handlers BEFORE blueprints to ensure they catch all errors
|
|
156
|
+
from app.error_handlers import register_error_handlers
|
|
157
|
+
register_error_handlers(app)
|
|
158
|
+
|
|
159
|
+
# Import and register blueprints
|
|
160
|
+
from app.blueprints.main import main_bp
|
|
161
|
+
from app.blueprints.auth import auth_bp
|
|
162
|
+
from app.blueprints.banking import banking_bp
|
|
163
|
+
from app.blueprints.mobile import mobile_bp
|
|
164
|
+
from app.blueprints.healthcare import healthcare_bp
|
|
165
|
+
from app.blueprints.compliance import compliance_bp
|
|
166
|
+
from app.blueprints.ecommerce import ecommerce_bp
|
|
167
|
+
from app.blueprints.checkout import checkout_bp
|
|
168
|
+
from app.blueprints.payments import payments_bp
|
|
169
|
+
from app.blueprints.loyalty import loyalty_bp
|
|
170
|
+
from app.blueprints.insurance import insurance_bp
|
|
171
|
+
from app.blueprints.infrastructure import infrastructure_bp
|
|
172
|
+
from app.blueprints.attack_sim import attack_sim_bp
|
|
173
|
+
from app.blueprints.ics_ot import ics_ot_bp
|
|
174
|
+
from app.blueprints.security_ops import security_ops_bp
|
|
175
|
+
from app.blueprints.integrations import integrations_bp
|
|
176
|
+
from app.blueprints.government import government_bp
|
|
177
|
+
from app.blueprints.saas import saas_bp
|
|
178
|
+
from app.blueprints.telecom import telecom_bp
|
|
179
|
+
from app.blueprints.energy_utilities import energy_utilities_bp
|
|
180
|
+
from app.blueprints.admin import admin_bp
|
|
181
|
+
from app.blueprints.testing import testing_bp
|
|
182
|
+
from app.blueprints.throughput import throughput_bp
|
|
183
|
+
from app.blueprints.genai import genai_bp
|
|
184
|
+
from app.blueprints.diagnostics import diagnostics_bp
|
|
185
|
+
from app.blueprints.recorder import recorder_bp
|
|
186
|
+
from app.middleware.traffic_recorder import TrafficRecorder
|
|
187
|
+
|
|
188
|
+
# Initialize Traffic Recorder
|
|
189
|
+
TrafficRecorder(app)
|
|
190
|
+
|
|
191
|
+
# Register all blueprints
|
|
192
|
+
app.register_blueprint(main_bp)
|
|
193
|
+
app.register_blueprint(auth_bp)
|
|
194
|
+
app.register_blueprint(banking_bp)
|
|
195
|
+
app.register_blueprint(mobile_bp)
|
|
196
|
+
app.register_blueprint(healthcare_bp)
|
|
197
|
+
app.register_blueprint(compliance_bp)
|
|
198
|
+
app.register_blueprint(ecommerce_bp)
|
|
199
|
+
app.register_blueprint(checkout_bp)
|
|
200
|
+
app.register_blueprint(payments_bp)
|
|
201
|
+
app.register_blueprint(loyalty_bp)
|
|
202
|
+
app.register_blueprint(insurance_bp)
|
|
203
|
+
app.register_blueprint(infrastructure_bp)
|
|
204
|
+
app.register_blueprint(attack_sim_bp)
|
|
205
|
+
app.register_blueprint(ics_ot_bp)
|
|
206
|
+
app.register_blueprint(security_ops_bp)
|
|
207
|
+
app.register_blueprint(integrations_bp)
|
|
208
|
+
app.register_blueprint(government_bp)
|
|
209
|
+
app.register_blueprint(saas_bp)
|
|
210
|
+
app.register_blueprint(telecom_bp)
|
|
211
|
+
app.register_blueprint(energy_utilities_bp)
|
|
212
|
+
app.register_blueprint(admin_bp)
|
|
213
|
+
app.register_blueprint(testing_bp)
|
|
214
|
+
app.register_blueprint(throughput_bp)
|
|
215
|
+
app.register_blueprint(genai_bp)
|
|
216
|
+
app.register_blueprint(diagnostics_bp)
|
|
217
|
+
app.register_blueprint(recorder_bp)
|
|
218
|
+
|
|
219
|
+
# Register database vulnerable endpoints (if database mode enabled)
|
|
220
|
+
if use_database:
|
|
221
|
+
from app.blueprints.database_vulnerable import db_vuln_bp
|
|
222
|
+
app.register_blueprint(db_vuln_bp)
|
|
223
|
+
print("✓ SQL injection test endpoints enabled")
|
|
224
|
+
|
|
225
|
+
# Static OpenAPI spec + Swagger UI
|
|
226
|
+
docs_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'docs'))
|
|
227
|
+
|
|
228
|
+
@app.get('/openapi.yaml')
|
|
229
|
+
def openapi_spec():
|
|
230
|
+
return send_from_directory(docs_dir, 'openapi.yaml')
|
|
231
|
+
|
|
232
|
+
@app.get('/swagger')
|
|
233
|
+
def swagger_ui():
|
|
234
|
+
html = """
|
|
235
|
+
<!doctype html>
|
|
236
|
+
<html lang="en">
|
|
237
|
+
<head>
|
|
238
|
+
<meta charset="utf-8" />
|
|
239
|
+
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
240
|
+
<title> TestBed Swagger UI</title>
|
|
241
|
+
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css" />
|
|
242
|
+
<style>
|
|
243
|
+
body { margin: 0; background: #0f172a; }
|
|
244
|
+
#swagger-ui { padding: 12px 24px; }
|
|
245
|
+
</style>
|
|
246
|
+
</head>
|
|
247
|
+
<body>
|
|
248
|
+
<div id="swagger-ui"></div>
|
|
249
|
+
<script src="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js"></script>
|
|
250
|
+
<script>
|
|
251
|
+
window.onload = function () {
|
|
252
|
+
SwaggerUIBundle({
|
|
253
|
+
url: '/openapi.yaml',
|
|
254
|
+
dom_id: '#swagger-ui',
|
|
255
|
+
deepLinking: true,
|
|
256
|
+
presets: [SwaggerUIBundle.presets.apis],
|
|
257
|
+
layout: 'BaseLayout'
|
|
258
|
+
});
|
|
259
|
+
};
|
|
260
|
+
</script>
|
|
261
|
+
</body>
|
|
262
|
+
</html>
|
|
263
|
+
"""
|
|
264
|
+
return Response(html, mimetype='text/html')
|
|
265
|
+
|
|
266
|
+
# Initialize demo data
|
|
267
|
+
with app.app_context():
|
|
268
|
+
from app.utils import init_demo_data
|
|
269
|
+
init_demo_data()
|
|
270
|
+
|
|
271
|
+
# --- SPA serving: bundle the React frontend into Flask ---
|
|
272
|
+
web_dist_dir = os.path.join(os.path.dirname(__file__), 'web_dist')
|
|
273
|
+
spa_index = os.path.join(web_dist_dir, 'index.html')
|
|
274
|
+
_API_PREFIXES = ('api/', 'apidocs', 'flasgger_static', 'apispec')
|
|
275
|
+
|
|
276
|
+
if os.path.isfile(spa_index):
|
|
277
|
+
print("✓ SPA mode — serving web portal from app/web_dist/")
|
|
278
|
+
|
|
279
|
+
# Replace the main blueprint's / handler instead of adding a
|
|
280
|
+
# duplicate URL rule (blueprint routes match before app routes).
|
|
281
|
+
def _serve_spa_index():
|
|
282
|
+
return send_from_directory(web_dist_dir, 'index.html')
|
|
283
|
+
|
|
284
|
+
app.view_functions['main.home'] = _serve_spa_index
|
|
285
|
+
|
|
286
|
+
@app.route('/<path:path>')
|
|
287
|
+
def spa_catch_all(path):
|
|
288
|
+
# Let API and Swagger routes return 404 so error handlers work
|
|
289
|
+
if path.startswith(_API_PREFIXES):
|
|
290
|
+
return jsonify({"error": "Not found"}), 404
|
|
291
|
+
|
|
292
|
+
# Serve actual static files (JS, CSS, images, etc.)
|
|
293
|
+
static_path = os.path.join(web_dist_dir, path)
|
|
294
|
+
if os.path.isfile(static_path):
|
|
295
|
+
return send_from_directory(web_dist_dir, path)
|
|
296
|
+
|
|
297
|
+
# Everything else → index.html (React Router handles it)
|
|
298
|
+
return send_from_directory(web_dist_dir, 'index.html')
|
|
299
|
+
else:
|
|
300
|
+
print("✓ API-only mode — no web_dist/index.html found")
|
|
301
|
+
|
|
302
|
+
return app
|