miso-client 0.1.0__py3-none-any.whl → 0.4.0__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.
Potentially problematic release.
This version of miso-client might be problematic. Click here for more details.
- miso_client/__init__.py +104 -84
- miso_client/errors.py +30 -4
- miso_client/models/__init__.py +4 -0
- miso_client/models/config.py +56 -35
- miso_client/models/error_response.py +41 -0
- miso_client/services/__init__.py +5 -5
- miso_client/services/auth.py +65 -48
- miso_client/services/cache.py +42 -41
- miso_client/services/encryption.py +18 -17
- miso_client/services/logger.py +115 -100
- miso_client/services/permission.py +27 -36
- miso_client/services/redis.py +17 -15
- miso_client/services/role.py +25 -36
- miso_client/utils/__init__.py +3 -3
- miso_client/utils/config_loader.py +24 -16
- miso_client/utils/data_masker.py +104 -33
- miso_client/utils/http_client.py +462 -254
- miso_client/utils/internal_http_client.py +471 -0
- miso_client/utils/jwt_tools.py +14 -17
- miso_client/utils/sensitive_fields_loader.py +116 -0
- {miso_client-0.1.0.dist-info → miso_client-0.4.0.dist-info}/METADATA +165 -3
- miso_client-0.4.0.dist-info/RECORD +26 -0
- miso_client-0.1.0.dist-info/RECORD +0 -23
- {miso_client-0.1.0.dist-info → miso_client-0.4.0.dist-info}/WHEEL +0 -0
- {miso_client-0.1.0.dist-info → miso_client-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {miso_client-0.1.0.dist-info → miso_client-0.4.0.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: miso-client
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Python client SDK for AI Fabrix authentication, authorization, and logging
|
|
5
5
|
Home-page: https://github.com/aifabrix/miso-client-python
|
|
6
6
|
Author: AI Fabrix Team
|
|
@@ -80,10 +80,13 @@ The **AI Fabrix Miso Client SDK** provides authentication, authorization, and lo
|
|
|
80
80
|
### 📊 Compliance & Audit
|
|
81
81
|
|
|
82
82
|
**ISO 27001 Compliance**
|
|
83
|
-
- Comprehensive audit trails for all user actions
|
|
83
|
+
- Comprehensive audit trails for all user actions and HTTP requests
|
|
84
|
+
- Automatic data masking for all sensitive information in logs
|
|
85
|
+
- HTTP request/response audit logging with masked sensitive data
|
|
84
86
|
- Data access logging and monitoring
|
|
85
87
|
- Security event tracking
|
|
86
88
|
- Accountability and non-repudiation
|
|
89
|
+
- Configurable sensitive fields via JSON configuration
|
|
87
90
|
|
|
88
91
|
**Regulatory Compliance**
|
|
89
92
|
- GDPR-ready data protection
|
|
@@ -134,9 +137,13 @@ The **AI Fabrix Miso Client SDK** provides authentication, authorization, and lo
|
|
|
134
137
|
|
|
135
138
|
**Observability**
|
|
136
139
|
- Centralized logging with correlation IDs
|
|
140
|
+
- Automatic HTTP request/response audit logging (ISO 27001 compliant)
|
|
141
|
+
- Debug logging with detailed request/response information (when `log_level='debug'`)
|
|
137
142
|
- Performance tracking and metrics
|
|
138
143
|
- Error tracking and debugging
|
|
139
144
|
- Health monitoring
|
|
145
|
+
- Automatic data masking for sensitive information in logs
|
|
146
|
+
- Configurable sensitive fields via JSON configuration
|
|
140
147
|
|
|
141
148
|
---
|
|
142
149
|
|
|
@@ -262,7 +269,7 @@ if is_admin:
|
|
|
262
269
|
|
|
263
270
|
### Step 5: Activate Logging
|
|
264
271
|
|
|
265
|
-
**What happens:** Application logs are sent to the Miso Controller with client token authentication.
|
|
272
|
+
**What happens:** Application logs are sent to the Miso Controller with client token authentication. All HTTP requests are automatically audited with ISO 27001 compliant data masking.
|
|
266
273
|
|
|
267
274
|
```python
|
|
268
275
|
from miso_client import MisoClient, load_config
|
|
@@ -278,10 +285,17 @@ user = await client.get_user(token)
|
|
|
278
285
|
await client.log.info('User accessed dashboard', {'userId': user.id if user else None})
|
|
279
286
|
await client.log.error('Operation failed', {'error': str(err)})
|
|
280
287
|
await client.log.warn('Unusual activity', {'details': '...'})
|
|
288
|
+
|
|
289
|
+
# HTTP requests are automatically audited
|
|
290
|
+
# All sensitive data is automatically masked before logging
|
|
291
|
+
result = await client.http_client.get('/api/users')
|
|
292
|
+
# This automatically creates an audit log: http.request.GET with masked sensitive data
|
|
281
293
|
```
|
|
282
294
|
|
|
283
295
|
**What happens to logs?** They're sent to the Miso Controller for centralized monitoring and analysis. Client token is automatically included.
|
|
284
296
|
|
|
297
|
+
**ISO 27001 Compliance:** All HTTP requests are automatically audited with sensitive data masked. Set `log_level='debug'` to enable detailed request/response logging (all sensitive data is still masked).
|
|
298
|
+
|
|
285
299
|
→ [Complete logging example](examples/step-5-logging.py)
|
|
286
300
|
→ [Logging Reference](docs/api-reference.md#logger-service)
|
|
287
301
|
|
|
@@ -366,6 +380,40 @@ ENCRYPTION_KEY=your-32-byte-encryption-key
|
|
|
366
380
|
|
|
367
381
|
---
|
|
368
382
|
|
|
383
|
+
### Testing with API Key
|
|
384
|
+
|
|
385
|
+
**What happens:** When `API_KEY` is set in your `.env` file, you can authenticate requests using the API key as a bearer token, bypassing OAuth2 authentication. This is useful for testing without setting up Keycloak.
|
|
386
|
+
|
|
387
|
+
```python
|
|
388
|
+
from miso_client import MisoClient, load_config
|
|
389
|
+
|
|
390
|
+
client = MisoClient(load_config())
|
|
391
|
+
await client.initialize()
|
|
392
|
+
|
|
393
|
+
# Use API_KEY as bearer token (for testing only)
|
|
394
|
+
api_key_token = "your-api-key-from-env"
|
|
395
|
+
is_valid = await client.validate_token(api_key_token)
|
|
396
|
+
# Returns True if token matches API_KEY from .env
|
|
397
|
+
|
|
398
|
+
user = await client.get_user(api_key_token)
|
|
399
|
+
# Returns None (API key auth doesn't provide user info)
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
**Configuration:**
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
# Add to .env for testing
|
|
406
|
+
API_KEY=your-test-api-key-here
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
**Important:**
|
|
410
|
+
- API_KEY authentication bypasses OAuth2 validation completely
|
|
411
|
+
- User information methods (`get_user()`, `get_user_info()`) return `None` when using API_KEY
|
|
412
|
+
- Token validation returns `True` if the bearer token matches the configured `API_KEY`
|
|
413
|
+
- This feature is intended for testing and development only
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
|
|
369
417
|
## 🔧 Configuration
|
|
370
418
|
|
|
371
419
|
```python
|
|
@@ -380,6 +428,8 @@ config = MisoClientConfig(
|
|
|
380
428
|
port=6379,
|
|
381
429
|
),
|
|
382
430
|
log_level="info", # Optional: 'debug' | 'info' | 'warn' | 'error'
|
|
431
|
+
# Set to 'debug' for detailed HTTP request/response logging
|
|
432
|
+
api_key="your-test-api-key", # Optional: API key for testing (bypasses OAuth2)
|
|
383
433
|
cache={ # Optional: Cache TTL settings
|
|
384
434
|
"role_ttl": 900, # Role cache TTL (default: 900s)
|
|
385
435
|
"permission_ttl": 900, # Permission cache TTL (default: 900s)
|
|
@@ -389,6 +439,18 @@ config = MisoClientConfig(
|
|
|
389
439
|
|
|
390
440
|
**Recommended:** Use `load_config()` to load from `.env` file automatically.
|
|
391
441
|
|
|
442
|
+
**ISO 27001 Data Masking Configuration:**
|
|
443
|
+
|
|
444
|
+
Sensitive fields are configured via `miso_client/utils/sensitive_fields_config.json`. You can customize this by:
|
|
445
|
+
|
|
446
|
+
1. Setting `MISO_SENSITIVE_FIELDS_CONFIG` environment variable to point to a custom JSON file
|
|
447
|
+
2. Using `DataMasker.set_config_path()` to set a custom path programmatically
|
|
448
|
+
|
|
449
|
+
The default configuration includes ISO 27001 compliant sensitive fields:
|
|
450
|
+
- Authentication: password, token, secret, key, auth, authorization
|
|
451
|
+
- PII: ssn, creditcard, cc, cvv, pin, otp
|
|
452
|
+
- Security: apikey, accesstoken, refreshtoken, privatekey, secretkey, cookie, session
|
|
453
|
+
|
|
392
454
|
→ [Complete Configuration Reference](docs/configuration.md)
|
|
393
455
|
|
|
394
456
|
---
|
|
@@ -413,6 +475,28 @@ The SDK consists of five core services:
|
|
|
413
475
|
- **LoggerService** - Centralized logging with API key authentication
|
|
414
476
|
- **RedisService** - Caching and queue management (optional)
|
|
415
477
|
|
|
478
|
+
### HTTP Client Architecture
|
|
479
|
+
|
|
480
|
+
The SDK uses a two-layer HTTP client architecture for ISO 27001 compliance:
|
|
481
|
+
|
|
482
|
+
- **InternalHttpClient** - Core HTTP functionality with automatic client token management (internal)
|
|
483
|
+
- **HttpClient** - Public wrapper that adds automatic ISO 27001 compliant audit and debug logging
|
|
484
|
+
|
|
485
|
+
**Features:**
|
|
486
|
+
- Automatic audit logging for all HTTP requests (`http.request.{METHOD}`)
|
|
487
|
+
- Debug logging when `log_level === 'debug'` with detailed request/response information
|
|
488
|
+
- Automatic data masking using `DataMasker` before logging (ISO 27001 compliant)
|
|
489
|
+
- Sensitive endpoints (`/api/logs`, `/api/auth/token`) are excluded from audit logging to prevent infinite loops
|
|
490
|
+
- All sensitive data (headers, bodies, query params) is automatically masked before logging
|
|
491
|
+
|
|
492
|
+
**ISO 27001 Compliance:**
|
|
493
|
+
- All request headers are masked (Authorization, x-client-token, Cookie, etc.)
|
|
494
|
+
- All request bodies are recursively masked for sensitive fields (password, token, secret, SSN, etc.)
|
|
495
|
+
- All response bodies are masked (limited to first 1000 characters)
|
|
496
|
+
- Query parameters are automatically masked
|
|
497
|
+
- Error messages are masked if they contain sensitive data
|
|
498
|
+
- Sensitive fields configuration can be customized via `sensitive_fields_config.json`
|
|
499
|
+
|
|
416
500
|
→ [Architecture Details](docs/api-reference.md#architecture)
|
|
417
501
|
|
|
418
502
|
---
|
|
@@ -450,6 +534,83 @@ The SDK consists of five core services:
|
|
|
450
534
|
- [Flask Decorators](docs/examples.md#flask-decorators) - Decorator-based auth
|
|
451
535
|
- [Error Handling](docs/examples.md#error-handling) - Best practices
|
|
452
536
|
|
|
537
|
+
---
|
|
538
|
+
|
|
539
|
+
### Structured Error Responses
|
|
540
|
+
|
|
541
|
+
**What happens:** The SDK automatically parses structured error responses from the API (RFC 7807-style format) and makes them available through the `MisoClientError` exception.
|
|
542
|
+
|
|
543
|
+
```python
|
|
544
|
+
from miso_client import MisoClient, MisoClientError, ErrorResponse, load_config
|
|
545
|
+
|
|
546
|
+
client = MisoClient(load_config())
|
|
547
|
+
await client.initialize()
|
|
548
|
+
|
|
549
|
+
try:
|
|
550
|
+
result = await client.http_client.get("/api/some-endpoint")
|
|
551
|
+
except MisoClientError as e:
|
|
552
|
+
# Check if structured error response is available
|
|
553
|
+
if e.error_response:
|
|
554
|
+
print(f"Error Type: {e.error_response.type}")
|
|
555
|
+
print(f"Error Title: {e.error_response.title}")
|
|
556
|
+
print(f"Status Code: {e.error_response.statusCode}")
|
|
557
|
+
print(f"Errors: {e.error_response.errors}")
|
|
558
|
+
print(f"Instance: {e.error_response.instance}")
|
|
559
|
+
else:
|
|
560
|
+
# Fallback to traditional error handling
|
|
561
|
+
print(f"Error: {e.message}")
|
|
562
|
+
print(f"Status Code: {e.status_code}")
|
|
563
|
+
print(f"Error Body: {e.error_body}")
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
**Error Response Structure:**
|
|
567
|
+
|
|
568
|
+
The `ErrorResponse` model follows RFC 7807-style format:
|
|
569
|
+
|
|
570
|
+
```json
|
|
571
|
+
{
|
|
572
|
+
"errors": [
|
|
573
|
+
"The user has provided input that the browser is unable to convert.",
|
|
574
|
+
"There are multiple rows in the database for the same value"
|
|
575
|
+
],
|
|
576
|
+
"type": "/Errors/Bad Input",
|
|
577
|
+
"title": "Bad Request",
|
|
578
|
+
"statusCode": 400,
|
|
579
|
+
"instance": "/OpenApi/rest/Xzy"
|
|
580
|
+
}
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
**Features:**
|
|
584
|
+
|
|
585
|
+
- **Automatic Parsing**: Structured error responses are automatically parsed from HTTP responses
|
|
586
|
+
- **Backward Compatible**: Falls back to traditional error handling when structured format is not available
|
|
587
|
+
- **Type Safety**: Full type hints with Pydantic models for reliable error handling
|
|
588
|
+
- **Generic Interface**: `ErrorResponse` model can be reused across different applications
|
|
589
|
+
- **Instance URI**: Automatically extracted from request URL if not provided in response
|
|
590
|
+
|
|
591
|
+
**Using ErrorResponse directly:**
|
|
592
|
+
|
|
593
|
+
```python
|
|
594
|
+
from miso_client import ErrorResponse
|
|
595
|
+
|
|
596
|
+
# Create ErrorResponse from dict
|
|
597
|
+
error_data = {
|
|
598
|
+
"errors": ["Validation failed"],
|
|
599
|
+
"type": "/Errors/Validation",
|
|
600
|
+
"title": "Validation Error",
|
|
601
|
+
"statusCode": 422,
|
|
602
|
+
"instance": "/api/endpoint"
|
|
603
|
+
}
|
|
604
|
+
error_response = ErrorResponse(**error_data)
|
|
605
|
+
|
|
606
|
+
# Access fields
|
|
607
|
+
print(error_response.errors) # ["Validation failed"]
|
|
608
|
+
print(error_response.type) # "/Errors/Validation"
|
|
609
|
+
print(error_response.title) # "Validation Error"
|
|
610
|
+
print(error_response.statusCode) # 422
|
|
611
|
+
print(error_response.instance) # "/api/endpoint"
|
|
612
|
+
```
|
|
613
|
+
|
|
453
614
|
### Common Tasks
|
|
454
615
|
|
|
455
616
|
**Add authentication middleware (FastAPI):**
|
|
@@ -490,6 +651,7 @@ MISO_CONTROLLER_URL=http://localhost:3000
|
|
|
490
651
|
REDIS_HOST=localhost
|
|
491
652
|
REDIS_PORT=6379
|
|
492
653
|
MISO_LOG_LEVEL=info
|
|
654
|
+
API_KEY=your-test-api-key # Optional: For testing (bypasses OAuth2)
|
|
493
655
|
```
|
|
494
656
|
|
|
495
657
|
---
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
miso_client/__init__.py,sha256=MjiF-VJCkY6_s5_Oy8U43ZRa-XRVgrTpco-PnGPBTC4,14395
|
|
2
|
+
miso_client/errors.py,sha256=uyS5j-_bUCA5gbINPYQd0wMpGsaEH0tJRK0obQTq2oo,1976
|
|
3
|
+
miso_client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
miso_client/models/__init__.py,sha256=lMnzU7j2Z5_UehvOeIrbJIo3MH4j5KINGfU1vJTzTyU,139
|
|
5
|
+
miso_client/models/config.py,sha256=TLckmwajrdnJpMTsjCtaFkz8wFAXcEQJfKjXQ8ww6vM,8024
|
|
6
|
+
miso_client/models/error_response.py,sha256=Dd-Rm2ylxU9ssYUsGBifjT-Let2MMxn28LJszQCO5bY,1362
|
|
7
|
+
miso_client/services/__init__.py,sha256=2ok62Z9kaS0Zze-OxRkxEJ4JidzN9jL_pzGMOxpZppQ,489
|
|
8
|
+
miso_client/services/auth.py,sha256=hYnHEoTNgeH_g0ItoVDq99fBZCZX0o-0o-9gRxqZYmw,5465
|
|
9
|
+
miso_client/services/cache.py,sha256=lXcLcRm56snOX3AQiEKi-j7FIikCLYnEK2HXxBkxm2M,6510
|
|
10
|
+
miso_client/services/encryption.py,sha256=8512ACLt0P8t3W_CGzmG0JRSvzDinvjPRvkifdDxIRs,3022
|
|
11
|
+
miso_client/services/logger.py,sha256=dopKQeBZpz9S3iX9vw8xcPsS1oyMASOUQ4-OvCdElTw,16772
|
|
12
|
+
miso_client/services/permission.py,sha256=GOGRAaXSfPKTXqEqbR0XP8hrA-YQgVFbHPxD-gGBUyA,6853
|
|
13
|
+
miso_client/services/redis.py,sha256=BWfgXoSOyyGrB9cf_kTY0lZwfbjUWQhkiOyFFSp590M,5348
|
|
14
|
+
miso_client/services/role.py,sha256=qmxhk54QUGCjCuCWm_ruDlTq7iT9yOicfUvdRVkFKUI,5517
|
|
15
|
+
miso_client/utils/__init__.py,sha256=HArSxVKrmCqFkqFOPwe1i3B2IBHJ1vRqYu98c_KASV0,366
|
|
16
|
+
miso_client/utils/config_loader.py,sha256=yZk4pXNIBu3i61KqxM8QwsjraM0xhqUcH2THl8-DMu0,3027
|
|
17
|
+
miso_client/utils/data_masker.py,sha256=D7AEyViGxoShLa5UUZHYhRCPQMPKqX7qNilTK9h87OM,7035
|
|
18
|
+
miso_client/utils/http_client.py,sha256=AwlP0h17SdJ2lqf5j19HVztjvvMrCPTybkbWdvGzM38,20252
|
|
19
|
+
miso_client/utils/internal_http_client.py,sha256=jgiaO94EiIUbMQWUKN4FhYqOQ9r0BZea0_grRcOepL4,16078
|
|
20
|
+
miso_client/utils/jwt_tools.py,sha256=-pvz5nk5BztEnhFnL-dtOv8Q5E0G2oh4RwFrVk2rVpg,1981
|
|
21
|
+
miso_client/utils/sensitive_fields_loader.py,sha256=EHODxyM1Gw7hgKXCvJ1B4Hf4LZqcEqWEXu4q5CPFaic,3667
|
|
22
|
+
miso_client-0.4.0.dist-info/licenses/LICENSE,sha256=3hoU8LdT9_EIFIx6FjMk5sQnVCBMX3FRIOzqqy5im4c,1076
|
|
23
|
+
miso_client-0.4.0.dist-info/METADATA,sha256=Ek0HsqCnGba1PhmwPWre-KSrxVcOthJ1XtDBuObGyUw,22690
|
|
24
|
+
miso_client-0.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
25
|
+
miso_client-0.4.0.dist-info/top_level.txt,sha256=8i_FNeRn8PRy6scnXOpVr-IJYsArkqIvxRMTZPtik9E,12
|
|
26
|
+
miso_client-0.4.0.dist-info/RECORD,,
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
miso_client/__init__.py,sha256=lL254-VN8Q8SV4nJwiTMYEWrYUpBzzG_uxNlNlQKuog,14205
|
|
2
|
-
miso_client/errors.py,sha256=XEa0bbYoP4mH6n8GuTquf-qD4tkCr-Ca3QIWOKZJtxQ,1143
|
|
3
|
-
miso_client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
miso_client/models/__init__.py,sha256=Oy03VQKAqg0FGZiWfcNdSgOA-PzfbdQDX_1sqfv_r-U,67
|
|
5
|
-
miso_client/models/config.py,sha256=PFiIp8fouoGGBUAu9ODwsVwhuW78v-iqEvDPBQ0YK5Q,7759
|
|
6
|
-
miso_client/services/__init__.py,sha256=DfiZJ45MWQvVqwp0kyxjuK9ngiO3nW8zcdBqd7VOD7Y,488
|
|
7
|
-
miso_client/services/auth.py,sha256=NrVX5MXaLqWinoWB7bAvEurTONkjVm2HlvDJPnmOkKU,4863
|
|
8
|
-
miso_client/services/cache.py,sha256=gu5Ykbh43vrBb9hLvl6OXstGKFZpUUyIAa4fifj6KW8,6786
|
|
9
|
-
miso_client/services/encryption.py,sha256=kQsES7oCs1l8vTmy1G9mI6eXXvrfdNuXMpZzG_xUX0M,3145
|
|
10
|
-
miso_client/services/logger.py,sha256=tpj-N3Rq4dfkJteNu7rt_KniOFkf5eyhuTbFcapM-Nk,16789
|
|
11
|
-
miso_client/services/permission.py,sha256=6vT9BV_NX9dJ7moSN5CBILjEn9u6do9IAeR4k3Fp9Q8,7210
|
|
12
|
-
miso_client/services/redis.py,sha256=4ov5Pu1xKDqSUNMDx9rTvbsTuM4jwaRUrpSiLAzIU_I,5478
|
|
13
|
-
miso_client/services/role.py,sha256=j4qCyYBXinubEpa0Yy_XPqFANuQHSQl0BILugRXM5WY,5896
|
|
14
|
-
miso_client/utils/__init__.py,sha256=YErXOQ6cqaxflEC7JCQuV_XbPU4NTAdBhbe4L5tv73o,365
|
|
15
|
-
miso_client/utils/config_loader.py,sha256=a2Jj8sd_IN8EhCjk3mtdMK1Z3MAG0P8IYThCd66dk3k,2912
|
|
16
|
-
miso_client/utils/data_masker.py,sha256=PJ-8ro2zuzS_XkjB5aV_DjY9NAjnlynJhsy41nFr408,4570
|
|
17
|
-
miso_client/utils/http_client.py,sha256=L9004iavGVM67BIJTl9_aI0rzV6fMSi0WPZi1h-CgTY,13347
|
|
18
|
-
miso_client/utils/jwt_tools.py,sha256=W1WFA_J1YU1Ng-IcsA9KdUTPda4pqIy7TF7nvXl2KLk,2061
|
|
19
|
-
miso_client-0.1.0.dist-info/licenses/LICENSE,sha256=3hoU8LdT9_EIFIx6FjMk5sQnVCBMX3FRIOzqqy5im4c,1076
|
|
20
|
-
miso_client-0.1.0.dist-info/METADATA,sha256=ocOKMvNYl5VKFXr5NbD7FtdwWfMM947h0Rt4lgLRJR0,16006
|
|
21
|
-
miso_client-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
22
|
-
miso_client-0.1.0.dist-info/top_level.txt,sha256=8i_FNeRn8PRy6scnXOpVr-IJYsArkqIvxRMTZPtik9E,12
|
|
23
|
-
miso_client-0.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|