araxys 0.1.0__tar.gz

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.
Files changed (36) hide show
  1. araxys-0.1.0/PKG-INFO +385 -0
  2. araxys-0.1.0/README.md +348 -0
  3. araxys-0.1.0/pyproject.toml +62 -0
  4. araxys-0.1.0/src/araxys/__init__.py +64 -0
  5. araxys-0.1.0/src/araxys/api_keys/__init__.py +1 -0
  6. araxys-0.1.0/src/araxys/api_keys/dependencies.py +71 -0
  7. araxys-0.1.0/src/araxys/api_keys/manager.py +194 -0
  8. araxys-0.1.0/src/araxys/api_keys/models.py +52 -0
  9. araxys-0.1.0/src/araxys/api_keys/storage.py +67 -0
  10. araxys-0.1.0/src/araxys/audit/__init__.py +1 -0
  11. araxys-0.1.0/src/araxys/audit/encryption.py +130 -0
  12. araxys-0.1.0/src/araxys/audit/events.py +9 -0
  13. araxys-0.1.0/src/araxys/audit/logger.py +114 -0
  14. araxys-0.1.0/src/araxys/core/__init__.py +1 -0
  15. araxys-0.1.0/src/araxys/core/config.py +167 -0
  16. araxys-0.1.0/src/araxys/core/exceptions.py +87 -0
  17. araxys-0.1.0/src/araxys/core/types.py +62 -0
  18. araxys-0.1.0/src/araxys/headers/__init__.py +1 -0
  19. araxys-0.1.0/src/araxys/headers/middleware.py +88 -0
  20. araxys-0.1.0/src/araxys/honeypot/__init__.py +1 -0
  21. araxys-0.1.0/src/araxys/honeypot/middleware.py +58 -0
  22. araxys-0.1.0/src/araxys/honeypot/trap.py +104 -0
  23. araxys-0.1.0/src/araxys/jwt_auth/__init__.py +1 -0
  24. araxys-0.1.0/src/araxys/jwt_auth/dependencies.py +92 -0
  25. araxys-0.1.0/src/araxys/jwt_auth/storage.py +76 -0
  26. araxys-0.1.0/src/araxys/jwt_auth/tokens.py +250 -0
  27. araxys-0.1.0/src/araxys/py.typed +0 -0
  28. araxys-0.1.0/src/araxys/rate_limit/__init__.py +1 -0
  29. araxys-0.1.0/src/araxys/rate_limit/backends.py +180 -0
  30. araxys-0.1.0/src/araxys/rate_limit/limiter.py +99 -0
  31. araxys-0.1.0/src/araxys/rate_limit/middleware.py +91 -0
  32. araxys-0.1.0/src/araxys/sanitize/__init__.py +1 -0
  33. araxys-0.1.0/src/araxys/sanitize/filters.py +165 -0
  34. araxys-0.1.0/src/araxys/sanitize/middleware.py +97 -0
  35. araxys-0.1.0/src/araxys/sanitize/patterns.py +215 -0
  36. araxys-0.1.0/src/araxys/shield.py +186 -0
araxys-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,385 @@
1
+ Metadata-Version: 2.3
2
+ Name: araxys
3
+ Version: 0.1.0
4
+ Summary: Plug & play security library for FastAPI — rate limiting, honeypots, JWT, API keys, and more.
5
+ Keywords: fastapi,security,rate-limiting,jwt,middleware,honeypot
6
+ Author: Andres Felipe Ramirez Muñoz
7
+ Author-email: Andres Felipe Ramirez Muñoz <andres.ramirez@porcicarnes.com>
8
+ License: MIT
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Framework :: FastAPI
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Topic :: Security
13
+ Classifier: Typing :: Typed
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Requires-Dist: fastapi>=0.115.0
16
+ Requires-Dist: pydantic>=2.0
17
+ Requires-Dist: pydantic-settings>=2.0
18
+ Requires-Dist: pyjwt[crypto]>=2.8
19
+ Requires-Dist: bleach>=6.0
20
+ Requires-Dist: cryptography>=44.0
21
+ Requires-Dist: structlog>=24.0
22
+ Requires-Dist: araxys[redis] ; extra == 'all'
23
+ Requires-Dist: pytest>=8.0 ; extra == 'dev'
24
+ Requires-Dist: pytest-asyncio>=0.23 ; extra == 'dev'
25
+ Requires-Dist: httpx>=0.27 ; extra == 'dev'
26
+ Requires-Dist: fakeredis>=2.21 ; extra == 'dev'
27
+ Requires-Dist: ruff>=0.11 ; extra == 'dev'
28
+ Requires-Dist: mypy>=1.10 ; extra == 'dev'
29
+ Requires-Dist: pre-commit>=4.0 ; extra == 'dev'
30
+ Requires-Dist: uvicorn>=0.30 ; extra == 'dev'
31
+ Requires-Dist: redis>=5.0 ; extra == 'redis'
32
+ Requires-Python: >=3.13
33
+ Provides-Extra: all
34
+ Provides-Extra: dev
35
+ Provides-Extra: redis
36
+ Description-Content-Type: text/markdown
37
+
38
+ <p align="center">
39
+ <img src="assets/araxyslogo.png" alt="Araxys Logo" width="400">
40
+ </p>
41
+
42
+ <p align="center">
43
+ <strong>Plug & Play Security for FastAPI</strong><br>
44
+ <em>Rate limiting · Honeypots · JWT · API Keys · Encrypted Audit Logging</em>
45
+ </p>
46
+
47
+ <p align="center">
48
+ <img src="https://img.shields.io/badge/python-3.13+-3776AB?style=for-the-badge&logo=python&logoColor=white" alt="Python">
49
+ <img src="https://img.shields.io/badge/FastAPI-0.115+-009688?style=for-the-badge&logo=fastapi&logoColor=white" alt="FastAPI">
50
+ <img src="https://img.shields.io/badge/Pydantic-v2-E92063?style=for-the-badge&logo=pydantic&logoColor=white" alt="Pydantic">
51
+ <img src="https://img.shields.io/badge/uv-package%20manager-DE5FE9?style=for-the-badge&logo=uv&logoColor=white" alt="uv">
52
+ <img src="https://img.shields.io/badge/license-MIT-green?style=for-the-badge" alt="License">
53
+ </p>
54
+
55
+ <p align="center">
56
+ <img src="https://img.shields.io/badge/encryption-AES--256--GCM-DC143C?style=flat-square" alt="AES-256-GCM">
57
+ <img src="https://img.shields.io/badge/JWT-OAuth2%20compliant-000000?style=flat-square&logo=jsonwebtokens&logoColor=white" alt="JWT">
58
+ <img src="https://img.shields.io/badge/Redis-optional-DC382D?style=flat-square&logo=redis&logoColor=white" alt="Redis">
59
+ <img src="https://img.shields.io/badge/structlog-logging-4B8BBE?style=flat-square" alt="structlog">
60
+ <img src="https://img.shields.io/badge/tests-63%20passed-brightgreen?style=flat-square" alt="Tests">
61
+ </p>
62
+
63
+ ---
64
+
65
+ ## ⚡ What is Araxys?
66
+
67
+ **Araxys** is a comprehensive security library for [FastAPI](https://fastapi.tiangolo.com/) that provides enterprise-grade protection with a plug & play architecture. Add security to your API with **three lines of code** — no rewrites, no boilerplate.
68
+
69
+ ```python
70
+ from fastapi import FastAPI
71
+ from araxys import AraxysShield, AraxysConfig
72
+
73
+ app = FastAPI()
74
+ shield = AraxysShield(app, AraxysConfig(secret_key="your-32-char-secret-key-here!!!!"))
75
+ # That's it. Your API is now protected. 🛡️
76
+ ```
77
+
78
+ ---
79
+
80
+ ## 🧩 Modules
81
+
82
+ | Module | Description | Status |
83
+ |--------|------------|--------|
84
+ | 🚦 **Rate Limiting** | Dynamic sliding window with escalating bans | ✅ Ready |
85
+ | 🍯 **Honeypots** | Fake endpoints that auto-ban bots | ✅ Ready |
86
+ | 🔑 **API Keys** | Scoped keys with SHA-256 hashing & expiration | ✅ Ready |
87
+ | 🎟️ **JWT Auth** | Access + Refresh tokens with rotation & revocation | ✅ Ready |
88
+ | 🛡️ **Secure Headers** | HSTS, CSP, X-Frame-Options & more (OWASP) | ✅ Ready |
89
+ | 🧹 **Sanitization** | SQLi detection & XSS stripping | ✅ Ready |
90
+ | 📋 **Audit Logging** | AES-256-GCM encrypted structured logs | ✅ Ready |
91
+
92
+ ---
93
+
94
+ ## 📦 Installation
95
+
96
+ ```bash
97
+ # Core (in-memory backends)
98
+ pip install araxys
99
+
100
+ # With Redis support (recommended for production)
101
+ pip install araxys[redis]
102
+
103
+ # Development
104
+ pip install araxys[dev]
105
+ ```
106
+
107
+ > **Requires Python 3.13+**
108
+
109
+ ---
110
+
111
+ ## 🚀 Quick Start
112
+
113
+ ### Full Protection (All Modules)
114
+
115
+ ```python
116
+ from fastapi import FastAPI
117
+ from araxys import AraxysShield, AraxysConfig
118
+
119
+ app = FastAPI()
120
+
121
+ shield = AraxysShield(
122
+ app,
123
+ AraxysConfig(
124
+ secret_key="super-secret-key-at-least-32-chars!",
125
+ redis_url="redis://localhost:6379", # Optional — omit for in-memory
126
+ rate_limit={"window_seconds": 60, "max_requests": 100},
127
+ honeypot={"paths": ["/admin/config", "/wp-admin", "/.env"]},
128
+ secure_headers=True,
129
+ sanitize=True,
130
+ audit={"encrypt": True, "log_file": "audit.log"},
131
+ ),
132
+ )
133
+ ```
134
+
135
+ ### API Key Authentication
136
+
137
+ ```python
138
+ from fastapi import Depends
139
+ from araxys import Scope
140
+ from araxys.api_keys.dependencies import require_api_key
141
+ from araxys.api_keys.models import APIKeyRecord
142
+
143
+ # Create a key
144
+ key = await shield.api_key_manager.create_key(
145
+ owner="service-a",
146
+ scopes=[Scope.READ, Scope.WRITE],
147
+ ttl_days=90,
148
+ )
149
+ print(f"Save this key: {key.raw_key}") # Shown only once!
150
+
151
+ # Protect an endpoint
152
+ @app.get("/data")
153
+ async def get_data(
154
+ key: APIKeyRecord = Depends(
155
+ require_api_key(Scope.READ, manager=shield.api_key_manager)
156
+ ),
157
+ ):
158
+ return {"data": "protected", "owner": key.owner}
159
+ ```
160
+
161
+ ### JWT with Token Rotation
162
+
163
+ ```python
164
+ from fastapi import Depends
165
+ from araxys import Scope
166
+ from araxys.jwt_auth.dependencies import require_jwt
167
+ from araxys.jwt_auth.tokens import TokenPayload
168
+
169
+ # Login — issue tokens
170
+ @app.post("/auth/login")
171
+ async def login(username: str, password: str):
172
+ # ... validate credentials ...
173
+ pair = await shield.jwt_manager.create_token_pair(
174
+ subject=user.id,
175
+ scopes=[Scope.READ, Scope.WRITE],
176
+ )
177
+ return pair.model_dump()
178
+
179
+ # Refresh — rotate tokens (old refresh token is blacklisted)
180
+ @app.post("/auth/refresh")
181
+ async def refresh(refresh_token: str):
182
+ new_pair = await shield.jwt_manager.rotate_tokens(refresh_token)
183
+ return new_pair.model_dump()
184
+
185
+ # Protected endpoint
186
+ @app.get("/profile")
187
+ async def profile(
188
+ user: TokenPayload = Depends(
189
+ require_jwt(Scope.READ, jwt_manager=shield.jwt_manager)
190
+ ),
191
+ ):
192
+ return {"user_id": user.sub, "scopes": user.scopes}
193
+ ```
194
+
195
+ ---
196
+
197
+ ## 🏗️ Architecture
198
+
199
+ ```
200
+ src/araxys/
201
+ ├── core/ # Config, exceptions, shared types
202
+ │ ├── config.py # Pydantic Settings (env var support)
203
+ │ ├── exceptions.py # Custom exception hierarchy
204
+ │ └── types.py # Scope, AuditEntry, SecurityContext
205
+ ├── rate_limit/ # 🚦 Dynamic rate limiting
206
+ │ ├── backends.py # Protocol + InMemory + Redis
207
+ │ ├── limiter.py # Sliding window + escalation
208
+ │ └── middleware.py # ASGI middleware
209
+ ├── honeypot/ # 🍯 Trap endpoints
210
+ │ ├── trap.py # Route registration + auto-ban
211
+ │ └── middleware.py # IP ban enforcement
212
+ ├── api_keys/ # 🔑 API Key management
213
+ │ ├── models.py # Pydantic models
214
+ │ ├── manager.py # CRUD + verification
215
+ │ ├── storage.py # Protocol + InMemory
216
+ │ └── dependencies.py # FastAPI dependencies
217
+ ├── jwt_auth/ # 🎟️ JWT tokens
218
+ │ ├── tokens.py # Create, decode, rotate
219
+ │ ├── storage.py # JTI blacklisting
220
+ │ └── dependencies.py # FastAPI dependencies
221
+ ├── headers/ # 🛡️ Security headers
222
+ │ └── middleware.py # HSTS, CSP, X-Frame-Options
223
+ ├── sanitize/ # 🧹 Input sanitization
224
+ │ ├── patterns.py # SQLi + XSS regex patterns
225
+ │ ├── filters.py # Detection + stripping
226
+ │ └── middleware.py # ASGI middleware
227
+ ├── audit/ # 📋 Audit logging
228
+ │ ├── encryption.py # AES-256-GCM + PBKDF2
229
+ │ ├── logger.py # Structured logger
230
+ │ └── events.py # Event types
231
+ └── shield.py # ⚡ Main orchestrator
232
+ ```
233
+
234
+ ---
235
+
236
+ ## 🔐 Security Features in Detail
237
+
238
+ ### Rate Limiting
239
+
240
+ - **Sliding window** counter per IP + endpoint
241
+ - **Escalating bans**: repeated violations increase ban duration exponentially
242
+ - **X-RateLimit headers**: `Limit`, `Remaining`, `Window` injected in every response
243
+ - **Path exclusion**: Skip `/docs`, `/healthz`, etc.
244
+
245
+ ### Honeypot Endpoints
246
+
247
+ - Registers **fake routes** like `/admin/config`, `/wp-admin`, `/.env`
248
+ - Returns **200 OK** with fake content (doesn't alert the bot)
249
+ - **Auto-bans the IP** across ALL endpoints
250
+ - Integrates with audit logging
251
+
252
+ ### API Key Management
253
+
254
+ - **256-bit entropy** keys via `secrets.token_urlsafe`
255
+ - Stored as **SHA-256 hashes** (raw key is never persisted)
256
+ - **Scope-based authorization**: `read`, `write`, `admin`
257
+ - **Expiration support** with configurable TTL
258
+ - **Pluggable storage**: implement the `APIKeyStorage` protocol with your database
259
+
260
+ ### JWT with Token Rotation
261
+
262
+ - **Access + Refresh** token pairs following OAuth2 best practices
263
+ - **JTI-based revocation**: each refresh token has a unique ID
264
+ - **Replay attack detection**: reusing a rotated refresh token triggers an alert
265
+ - **Configurable TTLs**: access (default 30min), refresh (default 7 days)
266
+ - **Scope embedding** in token claims
267
+
268
+ ### Secure Headers
269
+
270
+ | Header | Default Value |
271
+ |--------|--------------|
272
+ | `Strict-Transport-Security` | `max-age=31536000; includeSubDomains` |
273
+ | `X-Content-Type-Options` | `nosniff` |
274
+ | `X-Frame-Options` | `DENY` |
275
+ | `X-XSS-Protection` | `0` (disabled — modern best practice) |
276
+ | `Referrer-Policy` | `strict-origin-when-cross-origin` |
277
+ | `Content-Security-Policy` | Configurable |
278
+ | `Permissions-Policy` | Configurable |
279
+
280
+ ### Payload Sanitization
281
+
282
+ - **16 SQL injection patterns**: UNION, DROP, blind injection, time-based, etc.
283
+ - **9 XSS patterns**: script tags, JS URIs, event handlers, iframes
284
+ - **Recursive scanning** with configurable depth limit
285
+ - SQLi → **block** (400 response) · XSS → **strip** (bleach)
286
+
287
+ ### Encrypted Audit Logging
288
+
289
+ - **AES-256-GCM** authenticated encryption (confidentiality + integrity)
290
+ - **PBKDF2-HMAC-SHA256** key derivation (480,000 iterations — OWASP 2023)
291
+ - **Per-entry unique salt + nonce** (no two entries share the same key material)
292
+ - **Tamper detection**: GCM authentication tag catches any modification
293
+ - Structured output via **structlog**
294
+
295
+ ---
296
+
297
+ ## ⚙️ Configuration
298
+
299
+ All settings support **environment variables** with the `ARAXYS_` prefix:
300
+
301
+ ```bash
302
+ export ARAXYS_SECRET_KEY="your-production-secret-key-here!"
303
+ export ARAXYS_REDIS_URL="redis://localhost:6379"
304
+ ```
305
+
306
+ Or configure programmatically:
307
+
308
+ ```python
309
+ from araxys import AraxysConfig, RateLimitConfig, HoneypotConfig
310
+
311
+ config = AraxysConfig(
312
+ secret_key="...",
313
+ rate_limit=RateLimitConfig(
314
+ max_requests=200,
315
+ window_seconds=120,
316
+ ban_threshold=10,
317
+ ban_duration_seconds=600,
318
+ escalation_multiplier=3.0,
319
+ ),
320
+ honeypot=HoneypotConfig(
321
+ paths=["/admin", "/wp-login.php", "/.git/config"],
322
+ ban_duration_seconds=7200,
323
+ ),
324
+ jwt={"access_token_ttl_minutes": 15, "refresh_token_ttl_days": 30},
325
+ audit={"encrypt": True, "log_file": "/var/log/araxys/audit.log"},
326
+ )
327
+ ```
328
+
329
+ ---
330
+
331
+ ## 🧪 Testing
332
+
333
+ ```bash
334
+ # Run all tests
335
+ uv run pytest tests/ -v
336
+
337
+ # With coverage
338
+ uv run pytest tests/ --cov=araxys --cov-report=term-missing
339
+ ```
340
+
341
+ **63 tests** covering all 7 modules — rate limiting, honeypots, API keys, JWT, headers, sanitization, and audit logging.
342
+
343
+ ---
344
+
345
+ ## 🏭 Production Recommendations
346
+
347
+ | Aspect | Recommendation |
348
+ |--------|---------------|
349
+ | **Backends** | Use Redis (`araxys[redis]`) for multi-worker deployments |
350
+ | **Secret Key** | Generate with `openssl rand -hex 32` — never hardcode |
351
+ | **API Key Storage** | Implement `APIKeyStorage` protocol with your database |
352
+ | **Audit Logs** | Enable encryption + write to a dedicated log file |
353
+ | **Rate Limits** | Tune `max_requests` and `ban_threshold` per endpoint |
354
+ | **HTTPS** | Always deploy behind TLS — HSTS headers expect it |
355
+
356
+ ---
357
+
358
+ ## 📁 Tech Stack
359
+
360
+ <p align="center">
361
+ <img src="https://img.shields.io/badge/Python-3776AB?style=for-the-badge&logo=python&logoColor=white" alt="Python">
362
+ <img src="https://img.shields.io/badge/FastAPI-009688?style=for-the-badge&logo=fastapi&logoColor=white" alt="FastAPI">
363
+ <img src="https://img.shields.io/badge/Pydantic-E92063?style=for-the-badge&logo=pydantic&logoColor=white" alt="Pydantic">
364
+ <img src="https://img.shields.io/badge/JWT-000000?style=for-the-badge&logo=jsonwebtokens&logoColor=white" alt="JWT">
365
+ <img src="https://img.shields.io/badge/Redis-DC382D?style=for-the-badge&logo=redis&logoColor=white" alt="Redis">
366
+ <img src="https://img.shields.io/badge/structlog-4B8BBE?style=for-the-badge&logo=python&logoColor=white" alt="structlog">
367
+ <img src="https://img.shields.io/badge/cryptography-AES256-DC143C?style=for-the-badge" alt="cryptography">
368
+ <img src="https://img.shields.io/badge/pytest-0A9EDC?style=for-the-badge&logo=pytest&logoColor=white" alt="pytest">
369
+ <img src="https://img.shields.io/badge/Ruff-D7FF64?style=for-the-badge&logo=ruff&logoColor=black" alt="Ruff">
370
+ <img src="https://img.shields.io/badge/mypy-strict-blue?style=for-the-badge" alt="mypy">
371
+ <img src="https://img.shields.io/badge/uv-DE5FE9?style=for-the-badge&logo=uv&logoColor=white" alt="uv">
372
+ </p>
373
+
374
+ ---
375
+
376
+ ## 📄 License
377
+
378
+ MIT License — see [LICENSE](LICENSE) for details.
379
+
380
+ ---
381
+
382
+ <p align="center">
383
+ <strong>Built with 🛡️ by <a href="https://github.com/andresramirez">Samuel Esteban Urrego Valencia</a></strong><br>
384
+ <em>"Security shouldn't be an afterthought — it should be a single import."</em>
385
+ </p>