fastapi-payloadshield 1.0.0__tar.gz → 1.2.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 (50) hide show
  1. fastapi_payloadshield-1.2.0/PKG-INFO +257 -0
  2. fastapi_payloadshield-1.2.0/README.md +225 -0
  3. {fastapi_payloadshield-1.0.0 → fastapi_payloadshield-1.2.0}/document/DEVELOPMENT.md +35 -87
  4. fastapi_payloadshield-1.2.0/document/PROJECT_JOURNEY.md +105 -0
  5. {fastapi_payloadshield-1.0.0 → fastapi_payloadshield-1.2.0}/document/PUBLISHING_GUIDE.md +12 -11
  6. {fastapi_payloadshield-1.0.0 → fastapi_payloadshield-1.2.0}/examples/__init__.py +1 -1
  7. fastapi_payloadshield-1.2.0/examples/example_app.py +295 -0
  8. fastapi_payloadshield-1.2.0/examples/test_all_crypts.py +204 -0
  9. fastapi_payloadshield-1.2.0/fastapi_payloadshield/AESGCM256EncryptionHandler.py +65 -0
  10. fastapi_payloadshield-1.2.0/fastapi_payloadshield/Base64EncryptionHandler.py +33 -0
  11. fastapi_payloadshield-1.2.0/fastapi_payloadshield/EncryptionHandler.py +47 -0
  12. fastapi_payloadshield-1.2.0/fastapi_payloadshield/FernetEncryptionHandler.py +38 -0
  13. fastapi_payloadshield-1.2.0/fastapi_payloadshield/HybridRSAEncryptionHandler.py +93 -0
  14. fastapi_payloadshield-1.2.0/fastapi_payloadshield/__init__.py +42 -0
  15. fastapi_payloadshield-1.2.0/fastapi_payloadshield/config.py +53 -0
  16. fastapi_payloadshield-1.2.0/fastapi_payloadshield/crypto.py +55 -0
  17. fastapi_payloadshield-1.2.0/fastapi_payloadshield/decorators.py +174 -0
  18. fastapi_payloadshield-1.2.0/fastapi_payloadshield.egg-info/PKG-INFO +257 -0
  19. fastapi_payloadshield-1.2.0/fastapi_payloadshield.egg-info/SOURCES.txt +30 -0
  20. {fastapi_payloadshield-1.0.0 → fastapi_payloadshield-1.2.0}/fastapi_payloadshield.egg-info/requires.txt +1 -0
  21. {fastapi_payloadshield-1.0.0 → fastapi_payloadshield-1.2.0}/pyproject.toml +4 -4
  22. fastapi_payloadshield-1.2.0/setup.py +10 -0
  23. fastapi_payloadshield-1.2.0/tests/test_all_crypts.py +147 -0
  24. fastapi_payloadshield-1.2.0/tests/test_config.py +65 -0
  25. fastapi_payloadshield-1.2.0/tests/test_decorators.py +68 -0
  26. fastapi_payloadshield-1.2.0/tests/test_handlers.py +77 -0
  27. fastapi_payloadshield-1.0.0/PKG-INFO +0 -364
  28. fastapi_payloadshield-1.0.0/README.md +0 -327
  29. fastapi_payloadshield-1.0.0/document/COMPLETION_SUMMARY.md +0 -426
  30. fastapi_payloadshield-1.0.0/document/CUSTOM_HANDLERS.md +0 -391
  31. fastapi_payloadshield-1.0.0/document/DELIVERY_CHECKLIST.md +0 -386
  32. fastapi_payloadshield-1.0.0/document/FINAL_SUMMARY.md +0 -369
  33. fastapi_payloadshield-1.0.0/document/PACKAGE_SUMMARY.md +0 -361
  34. fastapi_payloadshield-1.0.0/document/PUBLICATION_READY.md +0 -337
  35. fastapi_payloadshield-1.0.0/document/QUICKSTART.md +0 -212
  36. fastapi_payloadshield-1.0.0/document/QUICK_REFERENCE.md +0 -367
  37. fastapi_payloadshield-1.0.0/document/REFACTORING_SUMMARY.md +0 -306
  38. fastapi_payloadshield-1.0.0/examples/example_app.py +0 -233
  39. fastapi_payloadshield-1.0.0/fastapi_payloadshield/__init__.py +0 -43
  40. fastapi_payloadshield-1.0.0/fastapi_payloadshield/crypto.py +0 -206
  41. fastapi_payloadshield-1.0.0/fastapi_payloadshield/decorators.py +0 -229
  42. fastapi_payloadshield-1.0.0/fastapi_payloadshield.egg-info/PKG-INFO +0 -364
  43. fastapi_payloadshield-1.0.0/fastapi_payloadshield.egg-info/SOURCES.txt +0 -27
  44. fastapi_payloadshield-1.0.0/setup.py +0 -46
  45. {fastapi_payloadshield-1.0.0 → fastapi_payloadshield-1.2.0}/LICENSE +0 -0
  46. {fastapi_payloadshield-1.0.0 → fastapi_payloadshield-1.2.0}/MANIFEST.in +0 -0
  47. {fastapi_payloadshield-1.0.0 → fastapi_payloadshield-1.2.0}/examples/test_client.py +0 -0
  48. {fastapi_payloadshield-1.0.0 → fastapi_payloadshield-1.2.0}/fastapi_payloadshield.egg-info/dependency_links.txt +0 -0
  49. {fastapi_payloadshield-1.0.0 → fastapi_payloadshield-1.2.0}/fastapi_payloadshield.egg-info/top_level.txt +0 -0
  50. {fastapi_payloadshield-1.0.0 → fastapi_payloadshield-1.2.0}/setup.cfg +0 -0
@@ -0,0 +1,257 @@
1
+ Metadata-Version: 2.4
2
+ Name: fastapi_payloadshield
3
+ Version: 1.2.0
4
+ Summary: Pluggable FastAPI decorators for encrypting/decrypting request and response payloads
5
+ Author-email: Ganesh Kandu <kanduganesh@gmail.com>
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/PayloadShield/FastAPIPS
8
+ Project-URL: Repository, https://github.com/PayloadShield/FastAPIPS.git
9
+ Project-URL: Issues, https://github.com/PayloadShield/FastAPIPS/issues
10
+ Keywords: fastapi,base64,crypto,encryption,decorator
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.7
13
+ Classifier: Programming Language :: Python :: 3.8
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Development Status :: 4 - Beta
19
+ Classifier: Intended Audience :: Developers
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Framework :: FastAPI
22
+ Requires-Python: >=3.7
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: fastapi>=0.68.0
26
+ Requires-Dist: starlette>=0.19.0
27
+ Requires-Dist: cryptography>=41.0.0
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=6.0; extra == "dev"
30
+ Requires-Dist: pytest-asyncio>=0.18.0; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # FastAPI Payload Shield
34
+
35
+ Pluggable FastAPI decorators for encrypting and decrypting request and
36
+ response payloads. Configure your keys once, then annotate any route with
37
+ `@PayloadShield.encrypt`, `@PayloadShield.decrypt`, or `@PayloadShield.crypt`.
38
+
39
+ > **Breaking change (v3.0.0)**: the old `encrypt_response` /
40
+ > `decrypt_request` / `crypto_middleware` decorators and the old
41
+ > `PayloadShieldEnc("base64")` factory function have been removed. There is
42
+ > no backward-compatible alias — see [Migrating to v3](#migrating-to-v3)
43
+ > below.
44
+
45
+ ## Key Features
46
+
47
+ - **Pluggable encryption**: base64, Fernet, AES-GCM-256, and Hybrid RSA+AES
48
+ ship out of the box; register your own with `register_handler(...)`.
49
+ - **One-time key configuration**: `PayloadShieldEnc.init({...})` sets keys
50
+ globally for all decorators.
51
+ - **Route-agnostic**: no changes needed to your route logic besides adding a
52
+ decorator.
53
+ - **Async-friendly**: works with FastAPI's async route handlers.
54
+
55
+ ## Installation
56
+
57
+ ```bash
58
+ pip install fastapi_payloadshield
59
+ ```
60
+
61
+ ## Quick Start
62
+
63
+ ```python
64
+ from fastapi import FastAPI
65
+ from fastapi_payloadshield import PayloadShield, PayloadShieldEnc
66
+
67
+ # Configure encryption keys once, at startup.
68
+ PayloadShieldEnc.init({
69
+ "Key": "my-symmetric-key",
70
+ })
71
+
72
+ app = FastAPI()
73
+
74
+ @app.get("/api/data")
75
+ @PayloadShield.encrypt("base64")
76
+ async def get_data():
77
+ return {"message": "hello", "data": "world"}
78
+
79
+ @app.post("/api/process")
80
+ @PayloadShield.decrypt("base64")
81
+ async def process_data(data: dict):
82
+ return {"received": data, "status": "success"}
83
+
84
+ @app.post("/api/secure")
85
+ @PayloadShield.crypt("base64")
86
+ async def secure_endpoint(data: dict):
87
+ return {"processed": data}
88
+ ```
89
+
90
+ ## Initialization: `PayloadShieldEnc.init(...)`
91
+
92
+ Call once before serving requests. Every decorator reads this shared
93
+ configuration at call time.
94
+
95
+ ```python
96
+ PayloadShieldEnc.init({
97
+ "Key": key, # symmetric key: fernet, aes-gcm-256
98
+ "PrivateKey": "string", # RSA/hybrid private key (file path or PEM content)
99
+ "PublicKey": "string", # RSA/hybrid public key (file path or PEM content)
100
+ })
101
+ ```
102
+
103
+ | Field | Used by | Accepts |
104
+ |---|---|---|
105
+ | `Key` | `fernet`, `aes-gcm-256` | Raw key string. `aes-gcm-256` requires the key to resolve to exactly 32 bytes (UTF-8 or base64 encoded). |
106
+ | `PrivateKey` | `rsa-hybrid` (decrypt) | File path to a PEM file, or the raw PEM content. |
107
+ | `PublicKey` | `rsa-hybrid` (encrypt) | File path to a PEM file, or the raw PEM content. |
108
+
109
+ Only set the fields required by the encryption types you actually use.
110
+
111
+ ## Decorators
112
+
113
+ All three live on the `PayloadShield` class and take an `encryption_type`
114
+ (default `"base64"`).
115
+
116
+ ### `@PayloadShield.encrypt(encryption_type)`
117
+
118
+ Encrypts the response payload only.
119
+
120
+ ```python
121
+ @app.get("/api/users")
122
+ @PayloadShield.encrypt("base64")
123
+ async def get_users():
124
+ return [{"id": 1, "name": "Alice"}]
125
+
126
+ # Response: {"encrypted": "W3siaWQiOiAxLCAibmFtZSI6ICJBbGljZSJ9XQ=="}
127
+ ```
128
+
129
+ ### `@PayloadShield.decrypt(encryption_type)`
130
+
131
+ Decrypts the request payload only; the route receives the decrypted dict.
132
+
133
+ ```python
134
+ @app.post("/api/login")
135
+ @PayloadShield.decrypt("base64")
136
+ async def login(credentials: dict):
137
+ return {"status": "success"}
138
+
139
+ # Expects: {"encrypted": "base64_encoded_json"}
140
+ ```
141
+
142
+ ### `@PayloadShield.crypt(encryption_type)`
143
+
144
+ Decrypts the request and encrypts the response.
145
+
146
+ ```python
147
+ @app.post("/api/secure")
148
+ @PayloadShield.crypt("base64")
149
+ async def secure_endpoint(data: dict):
150
+ return {"processed": data}
151
+
152
+ # Expects: {"encrypted": "encrypted_data"}
153
+ # Returns: {"encrypted": "encrypted_data"}
154
+ ```
155
+
156
+ ## Built-in Encryption Handlers
157
+
158
+ | Name | Algorithm | Keys required | Security |
159
+ |---|---|---|---|
160
+ | `base64` | Base64 encoding | none | None — obfuscation only |
161
+ | `fernet` | Fernet (AES-128-CBC + HMAC) | `Key` | Symmetric, authenticated |
162
+ | `aes-gcm-256` | AES-256-GCM | `Key` (32 bytes) | Symmetric, authenticated |
163
+ | `rsa-hybrid` | RSA-OAEP + AES-256-GCM | `PublicKey` (encrypt), `PrivateKey` (decrypt) | Asymmetric/hybrid |
164
+
165
+ ## Custom Handlers
166
+
167
+ Implement `EncryptionHandler` and register it — every decorator can then
168
+ use it by name.
169
+
170
+ ```python
171
+ from typing import Any, Dict, Optional
172
+ from fastapi_payloadshield import EncryptionHandler, register_handler, PayloadShield
173
+
174
+ class MyHandler(EncryptionHandler):
175
+ def encode(self, data: Any, config: Optional[Dict[str, Any]] = None) -> str:
176
+ ...
177
+
178
+ def decode(self, encoded_data: str, config: Optional[Dict[str, Any]] = None) -> Any:
179
+ ...
180
+
181
+ register_handler("my-handler", MyHandler())
182
+
183
+ @app.post("/api/custom")
184
+ @PayloadShield.crypt("my-handler")
185
+ async def custom_endpoint(data: dict):
186
+ return data
187
+ ```
188
+
189
+ `config` is the dict returned by `PayloadShieldEnc.get_config()` — pull out
190
+ whatever keys your handler needs (`Key`, `PrivateKey`, `PublicKey`).
191
+
192
+ ## How It Works
193
+
194
+ **Request decryption**: client sends `{"encrypted": "..."}` → decorator
195
+ decodes it with the configured handler → route receives the plain dict.
196
+
197
+ **Response encryption**: route returns a dict → decorator encodes it with
198
+ the configured handler → client receives `{"encrypted": "..."}`.
199
+
200
+ ## Errors
201
+
202
+ | Situation | Behavior |
203
+ |---|---|
204
+ | Request decryption fails | `400` response: `{"error": "Failed to decrypt request: ..."}` |
205
+ | Unknown `encryption_type` | `ValueError` raised when the decorator is applied: `Encryption handler '<name>' not found. Available handlers: ...` |
206
+ | Missing required key (e.g. no `Key` set for `fernet`) | `ValueError` raised when encoding/decoding: `... requires 'Key' to be set via PayloadShieldEnc.init(...)` |
207
+
208
+ ## Migrating to v3
209
+
210
+ | Removed (v2) | Replacement (v3) |
211
+ |---|---|
212
+ | `PayloadShieldEnc("base64")` (decorator factory) | `PayloadShield.encrypt("base64")` |
213
+ | `PayloadShieldDec("base64")` | `PayloadShield.decrypt("base64")` |
214
+ | `PayloadShield("base64")` (function call) | `PayloadShield.crypt("base64")` |
215
+ | `encrypt_response`, `decrypt_request`, `crypto_middleware` | Use the decorators above |
216
+ | No key configuration API | `PayloadShieldEnc.init({...})` |
217
+
218
+ There is no compatibility shim — update all call sites to the new API.
219
+
220
+ ## Testing
221
+
222
+ ```bash
223
+ # Run the example app
224
+ python examples/example_app.py
225
+
226
+ # Exercise it with the sample client
227
+ python examples/test_client.py
228
+
229
+ # Run the test suite
230
+ pytest
231
+ ```
232
+
233
+ ## Requirements
234
+
235
+ - Python 3.7+
236
+ - FastAPI 0.68+
237
+ - Starlette 0.19+
238
+ - cryptography 41+
239
+
240
+ ## Project Layout
241
+
242
+ - `fastapi_payloadshield/` - Main package
243
+ - `__init__.py` - Public exports
244
+ - `config.py` - `PayloadShieldEnc` key configuration
245
+ - `decorators.py` - `PayloadShield` decorators
246
+ - `crypto.py` - Handler registry (`register_handler`, `get_handler`)
247
+ - `EncryptionHandler.py`, `Base64EncryptionHandler.py`,
248
+ `FernetEncryptionHandler.py`, `AESGCM256EncryptionHandler.py`,
249
+ `HybridRSAEncryptionHandler.py` - Built-in handlers
250
+ - `examples/` - `example_app.py` demo app and `test_client.py` sample client
251
+ - `tests/` - pytest suite for handlers, config, and decorators
252
+ - `document/` - Additional guides (see [document/](document/))
253
+
254
+ ## License
255
+
256
+ Apache-2.0 - See [LICENSE](LICENSE) for details.
257
+
@@ -0,0 +1,225 @@
1
+ # FastAPI Payload Shield
2
+
3
+ Pluggable FastAPI decorators for encrypting and decrypting request and
4
+ response payloads. Configure your keys once, then annotate any route with
5
+ `@PayloadShield.encrypt`, `@PayloadShield.decrypt`, or `@PayloadShield.crypt`.
6
+
7
+ > **Breaking change (v3.0.0)**: the old `encrypt_response` /
8
+ > `decrypt_request` / `crypto_middleware` decorators and the old
9
+ > `PayloadShieldEnc("base64")` factory function have been removed. There is
10
+ > no backward-compatible alias — see [Migrating to v3](#migrating-to-v3)
11
+ > below.
12
+
13
+ ## Key Features
14
+
15
+ - **Pluggable encryption**: base64, Fernet, AES-GCM-256, and Hybrid RSA+AES
16
+ ship out of the box; register your own with `register_handler(...)`.
17
+ - **One-time key configuration**: `PayloadShieldEnc.init({...})` sets keys
18
+ globally for all decorators.
19
+ - **Route-agnostic**: no changes needed to your route logic besides adding a
20
+ decorator.
21
+ - **Async-friendly**: works with FastAPI's async route handlers.
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ pip install fastapi_payloadshield
27
+ ```
28
+
29
+ ## Quick Start
30
+
31
+ ```python
32
+ from fastapi import FastAPI
33
+ from fastapi_payloadshield import PayloadShield, PayloadShieldEnc
34
+
35
+ # Configure encryption keys once, at startup.
36
+ PayloadShieldEnc.init({
37
+ "Key": "my-symmetric-key",
38
+ })
39
+
40
+ app = FastAPI()
41
+
42
+ @app.get("/api/data")
43
+ @PayloadShield.encrypt("base64")
44
+ async def get_data():
45
+ return {"message": "hello", "data": "world"}
46
+
47
+ @app.post("/api/process")
48
+ @PayloadShield.decrypt("base64")
49
+ async def process_data(data: dict):
50
+ return {"received": data, "status": "success"}
51
+
52
+ @app.post("/api/secure")
53
+ @PayloadShield.crypt("base64")
54
+ async def secure_endpoint(data: dict):
55
+ return {"processed": data}
56
+ ```
57
+
58
+ ## Initialization: `PayloadShieldEnc.init(...)`
59
+
60
+ Call once before serving requests. Every decorator reads this shared
61
+ configuration at call time.
62
+
63
+ ```python
64
+ PayloadShieldEnc.init({
65
+ "Key": key, # symmetric key: fernet, aes-gcm-256
66
+ "PrivateKey": "string", # RSA/hybrid private key (file path or PEM content)
67
+ "PublicKey": "string", # RSA/hybrid public key (file path or PEM content)
68
+ })
69
+ ```
70
+
71
+ | Field | Used by | Accepts |
72
+ |---|---|---|
73
+ | `Key` | `fernet`, `aes-gcm-256` | Raw key string. `aes-gcm-256` requires the key to resolve to exactly 32 bytes (UTF-8 or base64 encoded). |
74
+ | `PrivateKey` | `rsa-hybrid` (decrypt) | File path to a PEM file, or the raw PEM content. |
75
+ | `PublicKey` | `rsa-hybrid` (encrypt) | File path to a PEM file, or the raw PEM content. |
76
+
77
+ Only set the fields required by the encryption types you actually use.
78
+
79
+ ## Decorators
80
+
81
+ All three live on the `PayloadShield` class and take an `encryption_type`
82
+ (default `"base64"`).
83
+
84
+ ### `@PayloadShield.encrypt(encryption_type)`
85
+
86
+ Encrypts the response payload only.
87
+
88
+ ```python
89
+ @app.get("/api/users")
90
+ @PayloadShield.encrypt("base64")
91
+ async def get_users():
92
+ return [{"id": 1, "name": "Alice"}]
93
+
94
+ # Response: {"encrypted": "W3siaWQiOiAxLCAibmFtZSI6ICJBbGljZSJ9XQ=="}
95
+ ```
96
+
97
+ ### `@PayloadShield.decrypt(encryption_type)`
98
+
99
+ Decrypts the request payload only; the route receives the decrypted dict.
100
+
101
+ ```python
102
+ @app.post("/api/login")
103
+ @PayloadShield.decrypt("base64")
104
+ async def login(credentials: dict):
105
+ return {"status": "success"}
106
+
107
+ # Expects: {"encrypted": "base64_encoded_json"}
108
+ ```
109
+
110
+ ### `@PayloadShield.crypt(encryption_type)`
111
+
112
+ Decrypts the request and encrypts the response.
113
+
114
+ ```python
115
+ @app.post("/api/secure")
116
+ @PayloadShield.crypt("base64")
117
+ async def secure_endpoint(data: dict):
118
+ return {"processed": data}
119
+
120
+ # Expects: {"encrypted": "encrypted_data"}
121
+ # Returns: {"encrypted": "encrypted_data"}
122
+ ```
123
+
124
+ ## Built-in Encryption Handlers
125
+
126
+ | Name | Algorithm | Keys required | Security |
127
+ |---|---|---|---|
128
+ | `base64` | Base64 encoding | none | None — obfuscation only |
129
+ | `fernet` | Fernet (AES-128-CBC + HMAC) | `Key` | Symmetric, authenticated |
130
+ | `aes-gcm-256` | AES-256-GCM | `Key` (32 bytes) | Symmetric, authenticated |
131
+ | `rsa-hybrid` | RSA-OAEP + AES-256-GCM | `PublicKey` (encrypt), `PrivateKey` (decrypt) | Asymmetric/hybrid |
132
+
133
+ ## Custom Handlers
134
+
135
+ Implement `EncryptionHandler` and register it — every decorator can then
136
+ use it by name.
137
+
138
+ ```python
139
+ from typing import Any, Dict, Optional
140
+ from fastapi_payloadshield import EncryptionHandler, register_handler, PayloadShield
141
+
142
+ class MyHandler(EncryptionHandler):
143
+ def encode(self, data: Any, config: Optional[Dict[str, Any]] = None) -> str:
144
+ ...
145
+
146
+ def decode(self, encoded_data: str, config: Optional[Dict[str, Any]] = None) -> Any:
147
+ ...
148
+
149
+ register_handler("my-handler", MyHandler())
150
+
151
+ @app.post("/api/custom")
152
+ @PayloadShield.crypt("my-handler")
153
+ async def custom_endpoint(data: dict):
154
+ return data
155
+ ```
156
+
157
+ `config` is the dict returned by `PayloadShieldEnc.get_config()` — pull out
158
+ whatever keys your handler needs (`Key`, `PrivateKey`, `PublicKey`).
159
+
160
+ ## How It Works
161
+
162
+ **Request decryption**: client sends `{"encrypted": "..."}` → decorator
163
+ decodes it with the configured handler → route receives the plain dict.
164
+
165
+ **Response encryption**: route returns a dict → decorator encodes it with
166
+ the configured handler → client receives `{"encrypted": "..."}`.
167
+
168
+ ## Errors
169
+
170
+ | Situation | Behavior |
171
+ |---|---|
172
+ | Request decryption fails | `400` response: `{"error": "Failed to decrypt request: ..."}` |
173
+ | Unknown `encryption_type` | `ValueError` raised when the decorator is applied: `Encryption handler '<name>' not found. Available handlers: ...` |
174
+ | Missing required key (e.g. no `Key` set for `fernet`) | `ValueError` raised when encoding/decoding: `... requires 'Key' to be set via PayloadShieldEnc.init(...)` |
175
+
176
+ ## Migrating to v3
177
+
178
+ | Removed (v2) | Replacement (v3) |
179
+ |---|---|
180
+ | `PayloadShieldEnc("base64")` (decorator factory) | `PayloadShield.encrypt("base64")` |
181
+ | `PayloadShieldDec("base64")` | `PayloadShield.decrypt("base64")` |
182
+ | `PayloadShield("base64")` (function call) | `PayloadShield.crypt("base64")` |
183
+ | `encrypt_response`, `decrypt_request`, `crypto_middleware` | Use the decorators above |
184
+ | No key configuration API | `PayloadShieldEnc.init({...})` |
185
+
186
+ There is no compatibility shim — update all call sites to the new API.
187
+
188
+ ## Testing
189
+
190
+ ```bash
191
+ # Run the example app
192
+ python examples/example_app.py
193
+
194
+ # Exercise it with the sample client
195
+ python examples/test_client.py
196
+
197
+ # Run the test suite
198
+ pytest
199
+ ```
200
+
201
+ ## Requirements
202
+
203
+ - Python 3.7+
204
+ - FastAPI 0.68+
205
+ - Starlette 0.19+
206
+ - cryptography 41+
207
+
208
+ ## Project Layout
209
+
210
+ - `fastapi_payloadshield/` - Main package
211
+ - `__init__.py` - Public exports
212
+ - `config.py` - `PayloadShieldEnc` key configuration
213
+ - `decorators.py` - `PayloadShield` decorators
214
+ - `crypto.py` - Handler registry (`register_handler`, `get_handler`)
215
+ - `EncryptionHandler.py`, `Base64EncryptionHandler.py`,
216
+ `FernetEncryptionHandler.py`, `AESGCM256EncryptionHandler.py`,
217
+ `HybridRSAEncryptionHandler.py` - Built-in handlers
218
+ - `examples/` - `example_app.py` demo app and `test_client.py` sample client
219
+ - `tests/` - pytest suite for handlers, config, and decorators
220
+ - `document/` - Additional guides (see [document/](document/))
221
+
222
+ ## License
223
+
224
+ Apache-2.0 - See [LICENSE](LICENSE) for details.
225
+
@@ -6,21 +6,31 @@
6
6
  FastAPIPS/
7
7
  ├── fastapi_payloadshield/ # Main package directory
8
8
  │ ├── __init__.py # Package initialization & exports
9
- │ ├── crypto.py # Base64 encoding/decoding utilities
10
- │ └── decorators.py # FastAPI decorators for encryption/decryption
9
+ │ ├── config.py # PayloadShieldEnc key configuration
10
+ │ ├── decorators.py # PayloadShield.encrypt/decrypt/crypt decorators
11
+ │ ├── crypto.py # Handler registry (register_handler/get_handler)
12
+ │ ├── EncryptionHandler.py # Abstract handler interface
13
+ │ ├── Base64EncryptionHandler.py # base64 handler
14
+ │ ├── FernetEncryptionHandler.py # fernet handler
15
+ │ ├── AESGCM256EncryptionHandler.py# aes-gcm-256 handler
16
+ │ └── HybridRSAEncryptionHandler.py# rsa-hybrid handler
11
17
  │
12
18
  ├── examples/ # Example implementations
13
19
  │ ├── example_app.py # Full-featured example FastAPI app
14
20
  │ └── test_client.py # Client script to test the API
15
21
  │
22
+ ├── tests/ # pytest suite
23
+ │ ├── test_handlers.py # Handler encode/decode roundtrip tests
24
+ │ ├── test_config.py # PayloadShieldEnc.init() tests
25
+ │ └── test_decorators.py # Decorator + FastAPI TestClient tests
26
+ │
16
27
  ├── setup.py # Classic setup configuration (pip installable)
17
28
  ├── pyproject.toml # Modern Python project configuration
18
29
  ├── requirements.txt # Development & runtime dependencies
19
- ├── README.md # Comprehensive documentation
20
- ├── QUICKSTART.md # Quick start guide
30
+ ├── README.md # Full API documentation
21
31
  ├── MANIFEST.in # Files to include in distribution
22
32
  ├── .gitignore # Git ignore patterns
23
- └── LICENSE # MIT License
33
+ └── LICENSE # Apache-2.0 License
24
34
  ```
25
35
 
26
36
  ## Installation for Development
@@ -78,72 +88,29 @@ curl -X POST http://localhost:8000/api/login \
78
88
  -d '{"encrypted":"eyJ1c2VybmFtZSI6ICJhZG1pbiIsICJwYXNzd29yZCI6ICJwYXNzd29yZDEyMyJ9"}'
79
89
  ```
80
90
 
81
- ## Package Components
82
-
83
- ### 1. `crypto.py` - Utilities
84
- - `encode_base64(data)` - Encode data to base64
85
- - `decode_base64(encoded_data)` - Decode base64 to data
86
- - `encode_response(data)` - Wrap response in encryption format
87
- - `decode_request(encoded_data)` - Decode request format
88
-
89
- ### 2. `decorators.py` - Decorators
90
- - `@encrypt_response` - Encrypts response payload
91
- - `@decrypt_request` - Decrypts request payload
92
- - `@crypto_middleware` - Combined encryption/decryption
93
-
94
- ## Adding New Features
95
-
96
- ### Add a New Decorator
97
- 1. Edit `fastapi_payloadshield/decorators.py`
98
- 2. Add your decorator function
99
- 3. Export it in `fastapi_payloadshield/__init__.py`
100
-
101
- Example:
102
- ```python
103
- # In decorators.py
104
- def my_new_decorator(func):
105
- @wraps(func)
106
- async def wrapper(*args, **kwargs):
107
- # Your logic here
108
- return await func(*args, **kwargs)
109
- return wrapper
110
-
111
- # In __init__.py
112
- from .decorators import my_new_decorator
113
- __all__ = [..., "my_new_decorator"]
91
+ ### Option 3: Run the pytest Suite
92
+ ```bash
93
+ pytest
114
94
  ```
115
95
 
116
- ### Add New Crypto Functions
117
- 1. Edit `fastapi_payloadshield/crypto.py`
118
- 2. Add your function
119
- 3. Export if needed in `__init__.py`
96
+ ## Package Components
120
97
 
121
- ## Publishing to PyPI
98
+ See [../README.md](../README.md) for the full API reference
99
+ (`PayloadShieldEnc.init`, `PayloadShield.encrypt/decrypt/crypt`, built-in
100
+ handlers, and custom handler registration). This guide only covers
101
+ day-to-day development workflows.
122
102
 
123
- ### 1. Update Version
124
- Edit version in:
125
- - `setup.py`
126
- - `pyproject.toml`
127
- - `fastapi_payloadshield/__init__.py`
103
+ ## Adding a New Built-in Handler
128
104
 
129
- ### 2. Install Build Tools
130
- ```bash
131
- pip install build twine
132
- ```
105
+ 1. Create `fastapi_payloadshield/MyHandler.py` implementing
106
+ `EncryptionHandler.encode(data, config)` / `.decode(encoded_data, config)`.
107
+ 2. Register it in `fastapi_payloadshield/crypto.py`'s `_HANDLERS` dict.
108
+ 3. Export the class from `fastapi_payloadshield/__init__.py`.
109
+ 4. Add a roundtrip test in `tests/test_handlers.py`.
133
110
 
134
- ### 3. Build Package
135
- ```bash
136
- python -m build
137
- ```
138
-
139
- ### 4. Upload to PyPI
140
- ```bash
141
- # Test PyPI first (optional)
142
- twine upload --repository testpypi dist/*
111
+ ## Publishing to PyPI
143
112
 
144
- # Production PyPI
145
- twine upload dist/*
146
- ```
113
+ See [PUBLISHING_GUIDE.md](PUBLISHING_GUIDE.md) for the full release process.
147
114
 
148
115
  ## Code Style
149
116
 
@@ -162,27 +129,6 @@ flake8 fastapi_payloadshield examples
162
129
  mypy fastapi_payloadshield
163
130
  ```
164
131
 
165
- ## Creating Tests
166
-
167
- Create a `tests/` directory with pytest tests:
168
-
169
- ```python
170
- # tests/test_crypto.py
171
- import pytest
172
- from fastapi_payloadshield.crypto import encode_base64, decode_base64
173
-
174
- def test_encode_decode():
175
- data = {"key": "value"}
176
- encoded = encode_base64(data)
177
- decoded = decode_base64(encoded)
178
- assert decoded == data
179
- ```
180
-
181
- Run tests:
182
- ```bash
183
- pytest
184
- ```
185
-
186
132
  ## Contributing
187
133
 
188
134
  1. Fork the repository
@@ -232,9 +178,11 @@ rm -rf build/ dist/ *.egg-info
232
178
 
233
179
  - [FastAPI Documentation](https://fastapi.tiangolo.com/)
234
180
  - [Python Packaging Guide](https://packaging.python.org/)
235
- - [Base64 RFC 4648](https://tools.ietf.org/html/rfc4648)
181
+ - [cryptography library](https://cryptography.io/)
236
182
  - [Setuptools Documentation](https://setuptools.readthedocs.io/)
237
183
 
238
184
  ## License
239
185
 
240
- MIT License - See LICENSE file for details
186
+ Apache-2.0 - See [../LICENSE](../LICENSE) for details.
187
+
188
+